aiobungie
A Pythonic async/await wrapper for interacting with the Bungie API.
Base client.
Example
import aiobungie
client = aiobungie.Client('YOUR_API_KEY')
# Search for Destiny2 users.
async def main() -> None:
users = await client.search_users('Crit')
# Iterate over the users and take the first 5 results.
for user in users.take(5):
print(f'{user.name} ({user.code})')
# Iterate through the users memberships.
for membership in user.memberships:
print(membership.type, membership.id)
client.run(main()) # or asyncio.run(main())
Single RESTClient instance.
The difference between base client and the REST clients:
- No Hight-Level concepts.
- All returned data are pure JSON objects from the API.
- No object creation.
Example
import aiobungie
async def main() -> None:
# Using `async with` context manager to close the session properly.
async with aiobungie.RESTClient("TOKEN") as rest:
payload = await rest.fetch_player('Fate怒', 4275)
for membership in payload:
print(membership['membershipId'], membership['iconPath'])
import asyncio
asyncio.run(main())
REST client pool.
A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.
Example
import aiobungie
import asyncio
pool = aiobungie.RESTPool("token")
async def func1() -> None:
async with pool.acquire() as instance:
tokens = await instance.fetch_oauth2_tokens('code')
pool.metadata['tokens'] = tokens
# Other instance may access the tokens from pool since its shared.
async def func2() -> None:
async with pool.acquire() as instance:
tokens = pool.metadata['tokens']
tokens = await instance.refresh_access_token(tokens.refresh_token)
async def main() -> None:
await asyncio.gather(func1(), func2())
asyncio.run(main())
Should you use the base client or the REST client? This returns to you. For an example if you're building a website.
You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.
Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
1# MIT License 2# 3# Copyright (c) 2020 - Present nxtlo 4# 5# Permission is hereby granted, free of charge, to any person obtaining a copy 6# of this software and associated documentation files (the "Software"), to deal 7# in the Software without restriction, including without limitation the rights 8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9# copies of the Software, and to permit persons to whom the Software is 10# furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice shall be included in all 13# copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21# SOFTWARE. 22 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API. 24 25Base client. 26 27Example 28------- 29```py 30import aiobungie 31 32client = aiobungie.Client('YOUR_API_KEY') 33 34# Search for Destiny2 users. 35async def main() -> None: 36 users = await client.search_users('Crit') 37 38 # Iterate over the users and take the first 5 results. 39 for user in users.take(5): 40 print(f'{user.name} ({user.code})') 41 42 # Iterate through the users memberships. 43 for membership in user.memberships: 44 print(membership.type, membership.id) 45 46client.run(main()) # or asyncio.run(main()) 47``` 48 49Single RESTClient instance. 50 51The difference between base client and the REST clients: 52 53* No Hight-Level concepts. 54* All returned data are pure JSON objects from the API. 55* No object creation. 56 57Example 58------- 59```py 60import aiobungie 61 62async def main() -> None: 63 # Using `async with` context manager to close the session properly. 64 async with aiobungie.RESTClient("TOKEN") as rest: 65 payload = await rest.fetch_player('Fate怒', 4275) 66 67 for membership in payload: 68 print(membership['membershipId'], membership['iconPath']) 69 70import asyncio 71asyncio.run(main()) 72``` 73 74REST client pool. 75 76A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection. 77 78Example 79------- 80```py 81import aiobungie 82import asyncio 83 84pool = aiobungie.RESTPool("token") 85 86async def func1() -> None: 87 async with pool.acquire() as instance: 88 tokens = await instance.fetch_oauth2_tokens('code') 89 pool.metadata['tokens'] = tokens 90 91# Other instance may access the tokens from pool since its shared. 92 93async def func2() -> None: 94 async with pool.acquire() as instance: 95 tokens = pool.metadata['tokens'] 96 tokens = await instance.refresh_access_token(tokens.refresh_token) 97 98async def main() -> None: 99 await asyncio.gather(func1(), func2()) 100 101asyncio.run(main()) 102``` 103 104Should you use the base client or the REST client? 105This returns to you. For an example if you're building a website. 106 107You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. 108Which gives you the freedom to deserialize it and implement your own logic in the front-end. 109 110Or of you're building a Discord bot for an example or something simple. The base client is the way to go. 111""" 112 113 114from __future__ import annotations 115 116from aiobungie import builders 117from aiobungie import crates 118from aiobungie import interfaces 119from aiobungie import traits 120from aiobungie import typedefs 121from aiobungie import url 122from aiobungie.client import Client 123from aiobungie.error import * 124from aiobungie.internal import iterators 125from aiobungie.internal.assets import Image 126from aiobungie.internal.enums import * 127from aiobungie.internal.factory import Factory 128from aiobungie.internal.iterators import * 129from aiobungie.rest import * 130from aiobungie.undefined import Undefined 131from aiobungie.undefined import UndefinedOr 132from aiobungie.undefined import UndefinedType 133 134from ._info import __about__ 135from ._info import __author__ 136from ._info import __docs__ 137from ._info import __email__ 138from ._info import __license__ 139from ._info import __url__ 140from ._info import __version__ 141 142# Alias for crate for backwards compatibility. 143crate = crates 144 145# Activity enums 146from .crates.activity import Difficulty 147 148# Components enums 149from .crates.components import ComponentFields 150from .crates.components import ComponentPrivacy 151 152# Entity enums 153from .crates.entity import GatingScope 154from .crates.entity import ObjectiveUIStyle 155from .crates.entity import ValueUIStyle 156 157# Fireteam enums. 158from .crates.fireteams import FireteamActivity 159from .crates.fireteams import FireteamDate 160from .crates.fireteams import FireteamLanguage 161from .crates.fireteams import FireteamPlatform 162 163# Records enums 164from .crates.records import RecordState 165 166__all__ = [mod for mod in dir() if not mod.startswith("_")] # type: ignore
60@attrs.define(auto_exc=True) 61class AiobungieError(RuntimeError): 62 """Base exception class that all other errors inherit from."""
Base exception class that all other errors inherit from.
Inherited Members
- builtins.BaseException
- with_traceback
- args
646@typing.final 647class AmmoType(int, Enum): 648 """AN enum for Detyiny 2 ammo types.""" 649 650 NONE = 0 651 PRIMARY = 1 652 SPECIAL = 2 653 HEAVY = 3
AN enum for Detyiny 2 ammo types.
160@attrs.define(auto_exc=True) 161class BadRequest(HTTPError): 162 """Bad requests exceptions.""" 163 164 url: typing.Optional[typedefs.StrOrURL] 165 """The URL/endpoint caused this error.""" 166 167 body: typing.Any 168 """The response body.""" 169 170 headers: multidict.CIMultiDictProxy[str] 171 """The response headers.""" 172 173 http_status: http.HTTPStatus = attrs.field(default=http.HTTPStatus.BAD_REQUEST)
Bad requests exceptions.
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = http_status 8 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status)
Method generated by attrs for class BadRequest.
76@helpers.deprecated("o.2.5", removed_in="0.2.6") 77@attrs.define(auto_exc=True) 78class CharacterError(HTTPError): 79 """Raised when a encountering making a character-based request. 80 81 .. warning:: 82 This is deprecated since 0.2.5 and will be removed in 0.2.6. 83 """
Raised when a encountering making a character-based request.
This is deprecated since 0.2.5 and will be removed in 0.2.6.
701@typing.final 702class ClanMemberType(int, Enum): 703 """An enum for bungie clan member types.""" 704 705 NONE = 0 706 BEGINNER = 1 707 MEMBER = 2 708 ADMIN = 3 709 ACTING_FOUNDER = 4 710 FOUNDER = 5
An enum for bungie clan member types.
477@typing.final 478class Class(int, Enum): 479 """An Enum for Destiny character classes.""" 480 481 TITAN = 0 482 HUNTER = 1 483 WARLOCK = 2 484 UNKNOWN = 3
An Enum for Destiny character classes.
61class Client(traits.ClientApp): 62 """Standard Bungie API client application. 63 64 This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory` 65 and returns `aiobungie.crates` Python object implementations of the responses. 66 67 A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts. 68 69 Parameters 70 ----------- 71 token: `str` 72 Your Bungie's API key or Token from the developer's portal. 73 74 Other Parameters 75 ---------------- 76 rest_client: `aiobungie.interfaces.RESTInterface | None` 77 An optional rest client instance you can pass. 78 If set to `None` then the client will use the default instance. 79 80 Example 81 ------- 82 ```py 83 TOKEN = "SOME_TOKEN" 84 async with aiobungie.RESTClient(TOKEN, max_retries=2) as rest_client: 85 client = aiobungie.Client(TOKEN, rest_client=rest_client) 86 ``` 87 88 max_retries : `int` 89 The max retries number to retry if the request hit a `5xx` status code. 90 max_ratelimit_retries : `int` 91 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 92 client_secret : `str | None` 93 An optional application client secret, 94 This is only needed if you're fetching OAuth2 tokens with this client. 95 client_id : `int | None` 96 An optional application client id, 97 This is only needed if you're fetching OAuth2 tokens with this client. 98 """ 99 100 __slots__ = ("_rest", "_factory", "_client_secret", "_client_id") 101 102 def __init__( 103 self, 104 token: str, 105 /, 106 client_secret: typing.Optional[str] = None, 107 client_id: typing.Optional[int] = None, 108 *, 109 rest_client: typing.Optional[interfaces.RESTInterface] = None, 110 max_retries: int = 4, 111 max_ratelimit_retries: int = 3, 112 ) -> None: 113 114 self._client_secret = client_secret 115 self._client_id = client_id 116 117 self._rest = ( 118 rest_client 119 if rest_client is not None 120 else rest_.RESTClient( 121 token, 122 client_secret, 123 client_id, 124 max_retries=max_retries, 125 max_ratelimit_retries=max_ratelimit_retries, 126 ) 127 ) 128 129 self._factory = factory_.Factory(self) 130 131 @property 132 def factory(self) -> factory_.Factory: 133 return self._factory 134 135 @property 136 def rest(self) -> interfaces.RESTInterface: 137 return self._rest 138 139 @property 140 def request(self) -> Client: 141 return copy.copy(self) 142 143 @property 144 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 145 return self._rest.metadata 146 147 def run( 148 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 149 ) -> None: 150 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 151 try: 152 if not loop.is_running(): 153 loop.set_debug(debug) 154 loop.run_until_complete(future) 155 156 except Exception as exc: 157 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 158 159 except KeyboardInterrupt: 160 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 161 return 162 163 finally: 164 if self._rest.is_alive: 165 # Clean up sessions. 166 loop.run_until_complete(self._rest.close()) 167 168 # * User methods. 169 170 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 171 """Fetch and return a user object of the bungie net user associated with account. 172 173 .. warning:: 174 This method requires OAuth2 scope and a Bearer access token. 175 176 Parameters 177 ---------- 178 access_token : `str` 179 A valid Bearer access token for the authorization. 180 181 Returns 182 ------- 183 `aiobungie.crates.user.User` 184 A user object includes the Destiny memberships and Bungie.net user. 185 """ 186 resp = await self.rest.fetch_current_user_memberships(access_token) 187 188 return self.factory.deserialize_user(resp) 189 190 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 191 """Fetch a Bungie user by their BungieNet id. 192 193 .. note:: 194 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 195 for other memberships. 196 197 Parameters 198 ---------- 199 id: `int` 200 The user id. 201 202 Returns 203 ------- 204 `aiobungie.crates.user.BungieUser` 205 A Bungie user. 206 207 Raises 208 ------ 209 `aiobungie.error.NotFound` 210 The user was not found. 211 """ 212 payload = await self.rest.fetch_bungie_user(id) 213 214 return self.factory.deserialize_bungie_user(payload) 215 216 async def search_users( 217 self, name: str, / 218 ) -> iterators.FlatIterator[user.SearchableDestinyUser]: 219 """Search for players and return all players that matches the same name. 220 221 Parameters 222 ---------- 223 name : `buildins.str` 224 The user name. 225 226 Returns 227 ------- 228 `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]` 229 A sequence of destiny memberships. 230 """ 231 payload = await self.rest.search_users(name) 232 233 return iterators.FlatIterator( 234 [ 235 self.factory.deserialize_searched_user(user) 236 for user in payload["searchResults"] 237 ] 238 ) 239 240 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 241 """Fetch all available user themes. 242 243 Returns 244 ------- 245 `collections.Sequence[aiobungie.crates.user.UserThemes]` 246 A sequence of user themes. 247 """ 248 data = await self.rest.fetch_user_themes() 249 250 return self.factory.deserialize_user_themes(data) 251 252 async def fetch_hard_types( 253 self, 254 credential: int, 255 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 256 /, 257 ) -> user.HardLinkedMembership: 258 """Gets any hard linked membership given a credential. 259 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 260 Cross Save aware. 261 262 Parameters 263 ---------- 264 credential: `int` 265 A valid SteamID64 266 type: `aiobungie.CredentialType` 267 The credential type. This must not be changed 268 Since its only credential that works "currently" 269 270 Returns 271 ------- 272 `aiobungie.crates.user.HardLinkedMembership` 273 Information about the hard linked data. 274 """ 275 276 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 277 278 return user.HardLinkedMembership( 279 id=int(payload["membershipId"]), 280 type=enums.MembershipType(payload["membershipType"]), 281 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 282 ) 283 284 async def fetch_membership_from_id( 285 self, 286 id: int, 287 /, 288 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 289 ) -> user.User: 290 """Fetch Bungie user's memberships from their id. 291 292 Notes 293 ----- 294 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 295 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 296 see `aiobungie.crates.user.DestinyMembership` for more details. 297 * If you only want the bungie user. Consider using `Client.fetch_user` method. 298 299 Parameters 300 ---------- 301 id : `int` 302 The user's id. 303 type : `aiobungie.MembershipType` 304 The user's membership type. 305 306 Returns 307 ------- 308 `aiobungie.crates.User` 309 A Bungie user with their membership types. 310 311 Raises 312 ------ 313 aiobungie.NotFound 314 The requested user was not found. 315 """ 316 payload = await self.rest.fetch_membership_from_id(id, type) 317 318 return self.factory.deserialize_user(payload) 319 320 async def fetch_user_credentials( 321 self, access_token: str, membership_id: int, / 322 ) -> collections.Sequence[user.UserCredentials]: 323 """Fetch an array of credential types attached to the requested account. 324 325 .. note:: 326 This method require OAuth2 Bearer access token. 327 328 Parameters 329 ---------- 330 access_token : `str` 331 The bearer access token associated with the bungie account. 332 membership_id : `int` 333 The id of the membership to return. 334 335 Returns 336 ------- 337 `collections.Sequence[aiobungie.crates.UserCredentials]` 338 A sequence of the attached user credentials. 339 340 Raises 341 ------ 342 `aiobungie.Unauthorized` 343 The access token was wrong or no access token passed. 344 """ 345 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 346 347 return self.factory.deserialize_user_credentials(resp) 348 349 # * Destiny 2. 350 351 async def fetch_profile( 352 self, 353 member_id: int, 354 type: typedefs.IntAnd[enums.MembershipType], 355 components: list[enums.ComponentType], 356 auth: typing.Optional[str] = None, 357 ) -> components.Component: 358 """ 359 Fetch a bungie profile passing components to the request. 360 361 Parameters 362 ---------- 363 member_id: `int` 364 The member's id. 365 type: `aiobungie.MembershipType` 366 A valid membership type. 367 components : `list[aiobungie.ComponentType]` 368 List of profile components to collect and return. 369 370 Other Parameters 371 ---------------- 372 auth : `typing.Optional[str]` 373 A Bearer access_token to make the request with. 374 This is optional and limited to components that only requires an Authorization token. 375 376 Returns 377 -------- 378 `aiobungie.crates.Component` 379 A Destiny 2 player profile with its components. 380 Only passed components will be available if they exists. Otherwise they will be `None` 381 382 Raises 383 ------ 384 `aiobungie.MembershipTypeError` 385 The provided membership type was invalid. 386 """ 387 data = await self.rest.fetch_profile(member_id, type, components, auth) 388 return self.factory.deserialize_components(data) 389 390 async def fetch_linked_profiles( 391 self, 392 member_id: int, 393 member_type: typedefs.IntAnd[enums.MembershipType], 394 /, 395 *, 396 all: bool = False, 397 ) -> profile.LinkedProfile: 398 """Returns a summary information about all profiles linked to the requested member. 399 400 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 401 402 .. note:: 403 It will only return linked accounts whose linkages you are allowed to view. 404 405 Parameters 406 ---------- 407 member_id : `int` 408 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 409 member_type : `aiobungie.MembershipType` 410 The type for the membership whose linked Destiny account you want to return. 411 412 Other Parameters 413 ---------------- 414 all : `bool` 415 If provided and set to `True`, All memberships regardless 416 of whether they're obscured by overrides will be returned, 417 418 If provided and set to `False`, Only available memberships will be returned. 419 The default for this is `False`. 420 421 Returns 422 ------- 423 `aiobungie.crates.profile.LinkedProfile` 424 A linked profile object. 425 """ 426 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 427 428 return self.factory.deserialize_linked_profiles(resp) 429 430 async def fetch_player( 431 self, 432 name: str, 433 code: int, 434 /, 435 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 436 ) -> collections.Sequence[user.DestinyMembership]: 437 """Fetch a Destiny 2 player's memberships. 438 439 Parameters 440 ----------- 441 name: `str` 442 The unique Bungie player name. 443 code : `int` 444 The unique Bungie display name code. 445 type: `aiobungie.internal.enums.MembershipType` 446 The player's membership type, e,g. XBOX, STEAM, PSN 447 448 Returns 449 -------- 450 `collections.Sequence[aiobungie.crates.DestinyMembership]` 451 A sequence of the found Destiny 2 player memberships. 452 An empty sequence will be returned if no one found. 453 454 Raises 455 ------ 456 `aiobungie.MembershipTypeError` 457 The provided membership type was invalid. 458 """ 459 resp = await self.rest.fetch_player(name, code, type) 460 461 return self.factory.deserialize_destiny_memberships(resp) 462 463 async def fetch_character( 464 self, 465 member_id: int, 466 membership_type: typedefs.IntAnd[enums.MembershipType], 467 character_id: int, 468 components: list[enums.ComponentType], 469 auth: typing.Optional[str] = None, 470 ) -> components.CharacterComponent: 471 """Fetch a Destiny 2 character. 472 473 Parameters 474 ---------- 475 member_id: `int` 476 A valid bungie member id. 477 character_id: `int` 478 The Destiny character id to retrieve. 479 membership_type: `aiobungie.internal.enums.MembershipType` 480 The member's membership type. 481 components: `list[aiobungie.ComponentType]` 482 Multiple arguments of character components to collect and return. 483 484 Other Parameters 485 ---------------- 486 auth : `typing.Optional[str]` 487 A Bearer access_token to make the request with. 488 This is optional and limited to components that only requires an Authorization token. 489 490 Returns 491 ------- 492 `aiobungie.crates.CharacterComponent` 493 A Bungie character component. 494 495 `aiobungie.MembershipTypeError` 496 The provided membership type was invalid. 497 """ 498 resp = await self.rest.fetch_character( 499 member_id, membership_type, character_id, components, auth 500 ) 501 502 return self.factory.deserialize_character_component(resp) 503 504 async def fetch_unique_weapon_history( 505 self, 506 membership_id: int, 507 character_id: int, 508 membership_type: typedefs.IntAnd[enums.MembershipType], 509 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 510 """Fetch details about unique weapon usage for a character. Includes all exotics. 511 512 Parameters 513 ---------- 514 membership_id : `int` 515 The Destiny user membership id. 516 character_id : `int` 517 The character id to retrieve. 518 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 519 The Destiny user's membership type. 520 521 Returns 522 ------- 523 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 524 A sequence of the weapon's extended values. 525 """ 526 resp = await self._rest.fetch_unique_weapon_history( 527 membership_id, character_id, membership_type 528 ) 529 530 return [ 531 self._factory.deserialize_extended_weapon_values(weapon) 532 for weapon in resp["weapons"] 533 ] 534 535 # * Destiny 2 Activities. 536 537 async def fetch_activities( 538 self, 539 member_id: int, 540 character_id: int, 541 mode: typedefs.IntAnd[enums.GameMode], 542 *, 543 membership_type: typedefs.IntAnd[ 544 enums.MembershipType 545 ] = enums.MembershipType.ALL, 546 page: int = 0, 547 limit: int = 250, 548 ) -> iterators.FlatIterator[activity.Activity]: 549 """Fetch a Destiny 2 activity for the specified character id. 550 551 Parameters 552 ---------- 553 member_id: `int` 554 The user id that starts with `4611`. 555 character_id: `int` 556 The id of the character to retrieve the activities for. 557 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 558 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 559 560 Other Parameters 561 ---------------- 562 membership_type: `aiobungie.internal.enums.MembershipType` 563 The Member ship type, if nothing was passed than it will return all. 564 page: int 565 The page number. Default is `0` 566 limit: int 567 Limit the returned result. Default is `250`. 568 569 Returns 570 ------- 571 `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]` 572 An iterator of the player's activities. 573 574 Raises 575 ------ 576 `aiobungie.MembershipTypeError` 577 The provided membership type was invalid. 578 """ 579 resp = await self.rest.fetch_activities( 580 member_id, 581 character_id, 582 mode, 583 membership_type=membership_type, 584 page=page, 585 limit=limit, 586 ) 587 588 return self.factory.deserialize_activities(resp) 589 590 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 591 """Fetch a post activity details. 592 593 Parameters 594 ---------- 595 instance_id: `int` 596 The activity instance id. 597 598 Returns 599 ------- 600 `aiobungie.crates.PostActivity` 601 A post activity object. 602 """ 603 resp = await self.rest.fetch_post_activity(instance_id) 604 605 return self.factory.deserialize_post_activity(resp) 606 607 async def fetch_aggregated_activity_stats( 608 self, 609 character_id: int, 610 membership_id: int, 611 membership_type: typedefs.IntAnd[enums.MembershipType], 612 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 613 """Fetch aggregated activity stats for a character. 614 615 Parameters 616 ---------- 617 character_id: `int` 618 The id of the character to retrieve the activities for. 619 membership_id: `int` 620 The id of the user that started with `4611`. 621 membership_type: `aiobungie.internal.enums.MembershipType` 622 The Member ship type. 623 624 Returns 625 ------- 626 `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]` 627 An iterator of the player's activities. 628 629 Raises 630 ------ 631 `aiobungie.MembershipTypeError` 632 The provided membership type was invalid. 633 """ 634 resp = await self.rest.fetch_aggregated_activity_stats( 635 character_id, membership_id, membership_type 636 ) 637 638 return self.factory.deserialize_aggregated_activities(resp) 639 640 # * Destiny 2 Clans or GroupsV2. 641 642 async def fetch_clan_from_id( 643 self, 644 id: int, 645 /, 646 access_token: typing.Optional[str] = None, 647 ) -> clans.Clan: 648 """Fetch a Bungie Clan by its id. 649 650 Parameters 651 ----------- 652 id: `int` 653 The clan id. 654 655 Returns 656 -------- 657 `aiobungie.crates.Clan` 658 An Bungie clan. 659 660 Raises 661 ------ 662 `aiobungie.NotFound` 663 The clan was not found. 664 """ 665 resp = await self.rest.fetch_clan_from_id(id, access_token) 666 667 return self.factory.deserialize_clan(resp) 668 669 async def fetch_clan( 670 self, 671 name: str, 672 /, 673 access_token: typing.Optional[str] = None, 674 *, 675 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 676 ) -> clans.Clan: 677 """Fetch a Clan by its name. 678 This method will return the first clan found with given name. 679 680 Parameters 681 ---------- 682 name: `str` 683 The clan name 684 685 Other Parameters 686 ---------------- 687 access_token : `typing.Optional[str]` 688 An optional access token to make the request with. 689 690 If the token was bound to a member of the clan, 691 This field `aiobungie.crates.Clan.current_user_membership` will be available 692 and will return the membership of the user who made this request. 693 type : `aiobungie.GroupType` 694 The group type, Default is aiobungie.GroupType.CLAN. 695 696 Returns 697 ------- 698 `aiobungie.crates.Clan` 699 A Bungie clan. 700 701 Raises 702 ------ 703 `aiobungie.NotFound` 704 The clan was not found. 705 """ 706 resp = await self.rest.fetch_clan(name, access_token, type=type) 707 708 return self.factory.deserialize_clan(resp) 709 710 async def fetch_clan_conversations( 711 self, clan_id: int, / 712 ) -> collections.Sequence[clans.ClanConversation]: 713 """Fetch the conversations/chat channels of the given clan id. 714 715 Parameters 716 ---------- 717 clan_id : `int` 718 The clan id. 719 720 Returns 721 `collections.Sequence[aiobungie.crates.ClanConversation]` 722 A sequence of the clan chat channels. 723 """ 724 resp = await self.rest.fetch_clan_conversations(clan_id) 725 726 return self.factory.deserialize_clan_conversations(resp) 727 728 async def fetch_clan_admins( 729 self, clan_id: int, / 730 ) -> iterators.FlatIterator[clans.ClanMember]: 731 """Fetch the clan founder and admins. 732 733 Parameters 734 ---------- 735 clan_id : `int` 736 The clan id. 737 738 Returns 739 ------- 740 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 741 An iterator over the found clan admins and founder. 742 743 Raises 744 ------ 745 `aiobungie.NotFound` 746 The requested clan was not found. 747 """ 748 resp = await self.rest.fetch_clan_admins(clan_id) 749 750 return self.factory.deserialize_clan_members(resp) 751 752 async def fetch_groups_for_member( 753 self, 754 member_id: int, 755 member_type: typedefs.IntAnd[enums.MembershipType], 756 /, 757 *, 758 filter: int = 0, 759 group_type: enums.GroupType = enums.GroupType.CLAN, 760 ) -> collections.Sequence[clans.GroupMember]: 761 """Fetch information about the groups that a given member has joined. 762 763 Parameters 764 ---------- 765 member_id : `int` 766 The member's id 767 member_type : `aiobungie.MembershipType` 768 The member's membership type. 769 770 Other Parameters 771 ---------------- 772 filter : `int` 773 Filter apply to list of joined groups. This Default to `0` 774 group_type : `aiobungie.GroupType` 775 The group's type. 776 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 777 778 Returns 779 ------- 780 `collections.Sequence[aiobungie.crates.GroupMember]` 781 A sequence of joined groups for the fetched member. 782 """ 783 resp = await self.rest.fetch_groups_for_member( 784 member_id, member_type, filter=filter, group_type=group_type 785 ) 786 787 return [ 788 self.factory.deserialize_group_member(group) for group in resp["results"] 789 ] 790 791 async def fetch_potential_groups_for_member( 792 self, 793 member_id: int, 794 member_type: typedefs.IntAnd[enums.MembershipType], 795 /, 796 *, 797 filter: int = 0, 798 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 799 ) -> collections.Sequence[clans.GroupMember]: 800 """Fetch the potential groups for a clan member. 801 802 Parameters 803 ---------- 804 member_id : `int` 805 The member's id 806 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 807 The member's membership type. 808 809 Other Parameters 810 ---------------- 811 filter : `int` 812 Filter apply to list of joined groups. This Default to `0` 813 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 814 The group's type. 815 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 816 817 Returns 818 ------- 819 `collections.Sequence[aiobungie.crates.GroupMember]` 820 A sequence of joined potential groups for the fetched member. 821 """ 822 resp = await self.rest.fetch_potential_groups_for_member( 823 member_id, member_type, filter=filter, group_type=group_type 824 ) 825 826 return [ 827 self.factory.deserialize_group_member(group) for group in resp["results"] 828 ] 829 830 async def fetch_clan_members( 831 self, 832 clan_id: int, 833 /, 834 *, 835 name: typing.Optional[str] = None, 836 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 837 ) -> iterators.FlatIterator[clans.ClanMember]: 838 """Fetch Bungie clan members. 839 840 Parameters 841 ---------- 842 clan_id : `int` 843 The clans id 844 845 Other Parameters 846 ---------------- 847 name : `typing.Optional[str]` 848 If provided, Only players matching this name will be returned. 849 type : `aiobungie.MembershipType` 850 An optional clan member's membership type. 851 This parameter is used to filter the returned results 852 by the provided membership, For an example XBox memberships only, 853 Otherwise will return all memberships. 854 855 Returns 856 ------- 857 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 858 An iterator over the bungie clan members. 859 860 Raises 861 ------ 862 `aiobungie.NotFound` 863 The clan was not found. 864 """ 865 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 866 867 return self.factory.deserialize_clan_members(resp) 868 869 async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]: 870 """Fetch the clan banners. 871 872 Returns 873 ------- 874 `collections.Sequence[aiobungie.crates.ClanBanner]` 875 A sequence of the clan banners. 876 """ 877 resp = await self.rest.fetch_clan_banners() 878 879 return self.factory.deserialize_clan_banners(resp) 880 881 # This method is required to be here since it deserialize the clan. 882 async def kick_clan_member( 883 self, 884 access_token: str, 885 /, 886 group_id: int, 887 membership_id: int, 888 membership_type: typedefs.IntAnd[enums.MembershipType], 889 ) -> clans.Clan: 890 """Kick a member from the clan. 891 892 .. note:: 893 This request requires OAuth2: oauth2: `AdminGroups` scope. 894 895 Parameters 896 ---------- 897 access_token : `str` 898 The bearer access token associated with the bungie account. 899 group_id: `int` 900 The group id. 901 membership_id : `int` 902 The member id to kick. 903 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 904 The member's membership type. 905 906 Returns 907 ------- 908 `aiobungie.crates.clan.Clan` 909 The clan that the member was kicked from. 910 """ 911 resp = await self.rest.kick_clan_member( 912 access_token, 913 group_id=group_id, 914 membership_id=membership_id, 915 membership_type=membership_type, 916 ) 917 918 return self.factory.deserialize_clan(resp) 919 920 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 921 """Fetch a Bungie clan's weekly reward state. 922 923 Parameters 924 ---------- 925 clan_id : `int` 926 The clan's id. 927 928 Returns 929 ------- 930 `aiobungie.crates.Milestone` 931 A runtime status of the clan's milestone data. 932 """ 933 934 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 935 936 return self.factory.deserialize_milestone(resp) 937 938 # * Destiny 2 Entities aka Definitions. 939 940 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 941 """Fetch a static inventory item entity given a its hash. 942 943 Parameters 944 ---------- 945 hash: `int` 946 Inventory item's hash. 947 948 Returns 949 ------- 950 `aiobungie.crates.InventoryEntity` 951 A bungie inventory item. 952 """ 953 resp = await self.rest.fetch_inventory_item(hash) 954 955 return self.factory.deserialize_inventory_entity(resp) 956 957 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 958 """Fetch a Destiny objective entity given a its hash. 959 960 Parameters 961 ---------- 962 hash: `int` 963 objective's hash. 964 965 Returns 966 ------- 967 `aiobungie.crates.ObjectiveEntity` 968 An objective entity item. 969 """ 970 resp = await self.rest.fetch_objective_entity(hash) 971 972 return self.factory.deserialize_objective_entity(resp) 973 974 async def search_entities( 975 self, name: str, entity_type: str, *, page: int = 0 976 ) -> iterators.FlatIterator[entity.SearchableEntity]: 977 """Search for Destiny2 entities given a name and its type. 978 979 Parameters 980 ---------- 981 name : `str` 982 The name of the entity, i.e., Thunderlord, One thousand voices. 983 entity_type : `str` 984 The type of the entity, AKA Definition, 985 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 986 987 Other Parameters 988 ---------------- 989 page : `int` 990 An optional page to return. Default to 0. 991 992 Returns 993 ------- 994 `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]` 995 An iterator over the found results matching the provided name. 996 """ 997 resp = await self.rest.search_entities(name, entity_type, page=page) 998 999 return self.factory.deserialize_inventory_results(resp) 1000 1001 # Fireteams 1002 1003 async def fetch_fireteams( 1004 self, 1005 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1006 *, 1007 platform: typedefs.IntAnd[ 1008 fireteams.FireteamPlatform 1009 ] = fireteams.FireteamPlatform.ANY, 1010 language: typing.Union[ 1011 fireteams.FireteamLanguage, str 1012 ] = fireteams.FireteamLanguage.ALL, 1013 date_range: int = 0, 1014 page: int = 0, 1015 slots_filter: int = 0, 1016 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1017 """Fetch public Bungie fireteams with open slots. 1018 1019 Parameters 1020 ---------- 1021 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1022 The fireteam activity type. 1023 1024 Other Parameters 1025 ---------------- 1026 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1027 If this is provided. Then the results will be filtered with the given platform. 1028 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1029 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1030 A locale language to filter the used language in that fireteam. 1031 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1032 date_range : `int` 1033 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1034 page : `int` 1035 The page number. By default its `0` which returns all available activities. 1036 slots_filter : `int` 1037 Filter the returned fireteams based on available slots. Default is `0` 1038 1039 Returns 1040 ------- 1041 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1042 A sequence of `aiobungie.crates.Fireteam` or `None`. 1043 """ 1044 1045 resp = await self.rest.fetch_fireteams( 1046 activity_type, 1047 platform=platform, 1048 language=language, 1049 date_range=date_range, 1050 page=page, 1051 slots_filter=slots_filter, 1052 ) 1053 1054 return self.factory.deserialize_fireteams(resp) 1055 1056 async def fetch_avaliable_clan_fireteams( 1057 self, 1058 access_token: str, 1059 group_id: int, 1060 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1061 *, 1062 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1063 language: typing.Union[fireteams.FireteamLanguage, str], 1064 date_range: int = 0, 1065 page: int = 0, 1066 public_only: bool = False, 1067 slots_filter: int = 0, 1068 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1069 """Fetch a clan's fireteams with open slots. 1070 1071 .. note:: 1072 This method requires OAuth2: ReadGroups scope. 1073 1074 Parameters 1075 ---------- 1076 access_token : `str` 1077 The bearer access token associated with the bungie account. 1078 group_id : `int` 1079 The group/clan id of the fireteam. 1080 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1081 The fireteam activity type. 1082 1083 Other Parameters 1084 ---------------- 1085 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1086 If this is provided. Then the results will be filtered with the given platform. 1087 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1088 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1089 A locale language to filter the used language in that fireteam. 1090 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1091 date_range : `int` 1092 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1093 page : `int` 1094 The page number. By default its `0` which returns all available activities. 1095 public_only: `bool` 1096 If set to True, Then only public fireteams will be returned. 1097 slots_filter : `int` 1098 Filter the returned fireteams based on available slots. Default is `0` 1099 1100 Returns 1101 ------- 1102 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1103 A sequence of fireteams found in the clan. 1104 `None` will be returned if nothing was found. 1105 """ 1106 resp = await self.rest.fetch_avaliable_clan_fireteams( 1107 access_token, 1108 group_id, 1109 activity_type, 1110 platform=platform, 1111 language=language, 1112 date_range=date_range, 1113 page=page, 1114 public_only=public_only, 1115 slots_filter=slots_filter, 1116 ) 1117 1118 return self.factory.deserialize_fireteams(resp) 1119 1120 async def fetch_clan_fireteam( 1121 self, access_token: str, fireteam_id: int, group_id: int 1122 ) -> fireteams.AvailableFireteam: 1123 """Fetch a specific clan fireteam. 1124 1125 .. note:: 1126 This method requires OAuth2: ReadGroups scope. 1127 1128 Parameters 1129 ---------- 1130 access_token : `str` 1131 The bearer access token associated with the bungie account. 1132 group_id : `int` 1133 The group/clan id to fetch the fireteam from. 1134 fireteam_id : `int` 1135 The fireteam id to fetch. 1136 1137 Returns 1138 ------- 1139 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1140 A sequence of available fireteams objects if exists. else `None` will be returned. 1141 """ 1142 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1143 1144 return self.factory.deserialize_available_fireteams( 1145 resp, no_results=True 1146 ) # type: ignore[return-value] 1147 1148 async def fetch_my_clan_fireteams( 1149 self, 1150 access_token: str, 1151 group_id: int, 1152 *, 1153 include_closed: bool = True, 1154 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1155 language: typing.Union[fireteams.FireteamLanguage, str], 1156 filtered: bool = True, 1157 page: int = 0, 1158 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1159 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1160 1161 .. note:: 1162 This method requires OAuth2: ReadGroups scope. 1163 1164 Parameters 1165 ---------- 1166 access_token : str 1167 The bearer access token associated with the bungie account. 1168 group_id : int 1169 The group/clan id to fetch. 1170 1171 Other Parameters 1172 ---------------- 1173 include_closed : bool 1174 If provided and set to True, It will also return closed fireteams. 1175 If provided and set to False, It will only return public fireteams. Default is True. 1176 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1177 If this is provided. Then the results will be filtered with the given platform. 1178 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1179 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1180 A locale language to filter the used language in that fireteam. 1181 Defaults to aiobungie.crates.FireteamLanguage.ALL 1182 filtered : bool 1183 If set to True, it will filter by clan. Otherwise not. Default is True. 1184 page : int 1185 The page number. By default its 0 which returns all available activities. 1186 1187 Returns 1188 ------- 1189 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1190 A sequence of available fireteams objects if exists. else `None` will be returned. 1191 """ 1192 resp = await self.rest.fetch_my_clan_fireteams( 1193 access_token, 1194 group_id, 1195 include_closed=include_closed, 1196 platform=platform, 1197 language=language, 1198 filtered=filtered, 1199 page=page, 1200 ) 1201 1202 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value] 1203 1204 # Friends and social. 1205 1206 async def fetch_friends( 1207 self, access_token: str, / 1208 ) -> collections.Sequence[friends.Friend]: 1209 """Fetch bungie friend list. 1210 1211 .. note:: 1212 This requests OAuth2: ReadUserData scope. 1213 1214 Parameters 1215 ----------- 1216 access_token : `str` 1217 The bearer access token associated with the bungie account. 1218 1219 Returns 1220 ------- 1221 `collections.Sequence[aiobungie.crates.Friend]` 1222 A sequence of the friends associated with that access token. 1223 """ 1224 1225 resp = await self.rest.fetch_friends(access_token) 1226 1227 return self.factory.deserialize_friends(resp) 1228 1229 async def fetch_friend_requests( 1230 self, access_token: str, / 1231 ) -> friends.FriendRequestView: 1232 """Fetch pending bungie friend requests queue. 1233 1234 .. note:: 1235 This requests OAuth2: ReadUserData scope. 1236 1237 Parameters 1238 ----------- 1239 access_token : `str` 1240 The bearer access token associated with the bungie account. 1241 1242 Returns 1243 ------- 1244 `aiobungie.crates.FriendRequestView` 1245 A friend requests view of that associated access token. 1246 """ 1247 1248 resp = await self.rest.fetch_friend_requests(access_token) 1249 1250 return self.factory.deserialize_friend_requests(resp) 1251 1252 # Applications and Developer portal. 1253 1254 async def fetch_application(self, appid: int, /) -> application.Application: 1255 """Fetch a Bungie application. 1256 1257 Parameters 1258 ----------- 1259 appid: `int` 1260 The application id. 1261 1262 Returns 1263 -------- 1264 `aiobungie.crates.Application` 1265 A Bungie application. 1266 """ 1267 resp = await self.rest.fetch_application(appid) 1268 1269 return self.factory.deserialize_app(resp) 1270 1271 # Milestones 1272 1273 async def fetch_public_milestone_content( 1274 self, milestone_hash: int, / 1275 ) -> milestones.MilestoneContent: 1276 """Fetch the milestone content given its hash. 1277 1278 Parameters 1279 ---------- 1280 milestone_hash : `int` 1281 The milestone hash. 1282 1283 Returns 1284 ------- 1285 `aiobungie.crates.milestones.MilestoneContent` 1286 A milestone content object. 1287 """ 1288 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1289 1290 return self.factory.deserialize_public_milestone_content(resp)
Standard Bungie API client application.
This client deserialize the REST JSON responses using aiobungie.Factory
and returns aiobungie.crates Python object implementations of the responses.
A aiobungie.RESTClient REST client can also be used alone for low-level concepts.
Parameters
- token (
str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
- rest_client (
aiobungie.interfaces.RESTInterface | None): An optional rest client instance you can pass. If set toNonethen the client will use the default instance.
Example
TOKEN = "SOME_TOKEN"
async with aiobungie.RESTClient(TOKEN, max_retries=2) as rest_client:
client = aiobungie.Client(TOKEN, rest_client=rest_client)
max_retries : int
The max retries number to retry if the request hit a 5xx status code.
max_ratelimit_retries : int
The max retries number to retry if the request hit a 429 status code. Defaults to 3.
client_secret : str | None
An optional application client secret,
This is only needed if you're fetching OAuth2 tokens with this client.
client_id : int | None
An optional application client id,
This is only needed if you're fetching OAuth2 tokens with this client.
102 def __init__( 103 self, 104 token: str, 105 /, 106 client_secret: typing.Optional[str] = None, 107 client_id: typing.Optional[int] = None, 108 *, 109 rest_client: typing.Optional[interfaces.RESTInterface] = None, 110 max_retries: int = 4, 111 max_ratelimit_retries: int = 3, 112 ) -> None: 113 114 self._client_secret = client_secret 115 self._client_id = client_id 116 117 self._rest = ( 118 rest_client 119 if rest_client is not None 120 else rest_.RESTClient( 121 token, 122 client_secret, 123 client_id, 124 max_retries=max_retries, 125 max_ratelimit_retries=max_ratelimit_retries, 126 ) 127 ) 128 129 self._factory = factory_.Factory(self)
A mutable mapping storage for the user's needs.
147 def run( 148 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 149 ) -> None: 150 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 151 try: 152 if not loop.is_running(): 153 loop.set_debug(debug) 154 loop.run_until_complete(future) 155 156 except Exception as exc: 157 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 158 159 except KeyboardInterrupt: 160 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 161 return 162 163 finally: 164 if self._rest.is_alive: 165 # Clean up sessions. 166 loop.run_until_complete(self._rest.close())
Runs a coroutine function until its complete.
This is equivalent to asyncio.get_event_loop().run_until_complete(...)
Parameters
- future (
collections.Coroutine[None, None, None]): A coroutine object. - debug (
bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
await fetch(...)
# Run the coroutine.
client.run(main())
170 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 171 """Fetch and return a user object of the bungie net user associated with account. 172 173 .. warning:: 174 This method requires OAuth2 scope and a Bearer access token. 175 176 Parameters 177 ---------- 178 access_token : `str` 179 A valid Bearer access token for the authorization. 180 181 Returns 182 ------- 183 `aiobungie.crates.user.User` 184 A user object includes the Destiny memberships and Bungie.net user. 185 """ 186 resp = await self.rest.fetch_current_user_memberships(access_token) 187 188 return self.factory.deserialize_user(resp)
Fetch and return a user object of the bungie net user associated with account.
This method requires OAuth2 scope and a Bearer access token.
Parameters
- access_token (
str): A valid Bearer access token for the authorization.
Returns
aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
190 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 191 """Fetch a Bungie user by their BungieNet id. 192 193 .. note:: 194 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 195 for other memberships. 196 197 Parameters 198 ---------- 199 id: `int` 200 The user id. 201 202 Returns 203 ------- 204 `aiobungie.crates.user.BungieUser` 205 A Bungie user. 206 207 Raises 208 ------ 209 `aiobungie.error.NotFound` 210 The user was not found. 211 """ 212 payload = await self.rest.fetch_bungie_user(id) 213 214 return self.factory.deserialize_bungie_user(payload)
Fetch a Bungie user by their BungieNet id.
This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id
for other memberships.
Parameters
- id (
int): The user id.
Returns
aiobungie.crates.user.BungieUser: A Bungie user.
Raises
aiobungie.NotFound: The user was not found.
216 async def search_users( 217 self, name: str, / 218 ) -> iterators.FlatIterator[user.SearchableDestinyUser]: 219 """Search for players and return all players that matches the same name. 220 221 Parameters 222 ---------- 223 name : `buildins.str` 224 The user name. 225 226 Returns 227 ------- 228 `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]` 229 A sequence of destiny memberships. 230 """ 231 payload = await self.rest.search_users(name) 232 233 return iterators.FlatIterator( 234 [ 235 self.factory.deserialize_searched_user(user) 236 for user in payload["searchResults"] 237 ] 238 )
Search for players and return all players that matches the same name.
Parameters
- name (
buildins.str): The user name.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]: A sequence of destiny memberships.
240 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 241 """Fetch all available user themes. 242 243 Returns 244 ------- 245 `collections.Sequence[aiobungie.crates.user.UserThemes]` 246 A sequence of user themes. 247 """ 248 data = await self.rest.fetch_user_themes() 249 250 return self.factory.deserialize_user_themes(data)
Fetch all available user themes.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
252 async def fetch_hard_types( 253 self, 254 credential: int, 255 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 256 /, 257 ) -> user.HardLinkedMembership: 258 """Gets any hard linked membership given a credential. 259 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 260 Cross Save aware. 261 262 Parameters 263 ---------- 264 credential: `int` 265 A valid SteamID64 266 type: `aiobungie.CredentialType` 267 The credential type. This must not be changed 268 Since its only credential that works "currently" 269 270 Returns 271 ------- 272 `aiobungie.crates.user.HardLinkedMembership` 273 Information about the hard linked data. 274 """ 275 276 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 277 278 return user.HardLinkedMembership( 279 id=int(payload["membershipId"]), 280 type=enums.MembershipType(payload["membershipType"]), 281 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 282 )
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
284 async def fetch_membership_from_id( 285 self, 286 id: int, 287 /, 288 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 289 ) -> user.User: 290 """Fetch Bungie user's memberships from their id. 291 292 Notes 293 ----- 294 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 295 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 296 see `aiobungie.crates.user.DestinyMembership` for more details. 297 * If you only want the bungie user. Consider using `Client.fetch_user` method. 298 299 Parameters 300 ---------- 301 id : `int` 302 The user's id. 303 type : `aiobungie.MembershipType` 304 The user's membership type. 305 306 Returns 307 ------- 308 `aiobungie.crates.User` 309 A Bungie user with their membership types. 310 311 Raises 312 ------ 313 aiobungie.NotFound 314 The requested user was not found. 315 """ 316 payload = await self.rest.fetch_membership_from_id(id, type) 317 318 return self.factory.deserialize_user(payload)
Fetch Bungie user's memberships from their id.
Notes
- This returns both BungieNet membership and a sequence of the player's DestinyMemberships
Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
see
aiobungie.crates.user.DestinyMembershipfor more details. - If you only want the bungie user. Consider using
Client.fetch_usermethod.
Parameters
- id (
int): The user's id. - type (
aiobungie.MembershipType): The user's membership type.
Returns
aiobungie.crates.User: A Bungie user with their membership types.
Raises
- aiobungie.NotFound: The requested user was not found.
320 async def fetch_user_credentials( 321 self, access_token: str, membership_id: int, / 322 ) -> collections.Sequence[user.UserCredentials]: 323 """Fetch an array of credential types attached to the requested account. 324 325 .. note:: 326 This method require OAuth2 Bearer access token. 327 328 Parameters 329 ---------- 330 access_token : `str` 331 The bearer access token associated with the bungie account. 332 membership_id : `int` 333 The id of the membership to return. 334 335 Returns 336 ------- 337 `collections.Sequence[aiobungie.crates.UserCredentials]` 338 A sequence of the attached user credentials. 339 340 Raises 341 ------ 342 `aiobungie.Unauthorized` 343 The access token was wrong or no access token passed. 344 """ 345 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 346 347 return self.factory.deserialize_user_credentials(resp)
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of the attached user credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
351 async def fetch_profile( 352 self, 353 member_id: int, 354 type: typedefs.IntAnd[enums.MembershipType], 355 components: list[enums.ComponentType], 356 auth: typing.Optional[str] = None, 357 ) -> components.Component: 358 """ 359 Fetch a bungie profile passing components to the request. 360 361 Parameters 362 ---------- 363 member_id: `int` 364 The member's id. 365 type: `aiobungie.MembershipType` 366 A valid membership type. 367 components : `list[aiobungie.ComponentType]` 368 List of profile components to collect and return. 369 370 Other Parameters 371 ---------------- 372 auth : `typing.Optional[str]` 373 A Bearer access_token to make the request with. 374 This is optional and limited to components that only requires an Authorization token. 375 376 Returns 377 -------- 378 `aiobungie.crates.Component` 379 A Destiny 2 player profile with its components. 380 Only passed components will be available if they exists. Otherwise they will be `None` 381 382 Raises 383 ------ 384 `aiobungie.MembershipTypeError` 385 The provided membership type was invalid. 386 """ 387 data = await self.rest.fetch_profile(member_id, type, components, auth) 388 return self.factory.deserialize_components(data)
Fetch a bungie profile passing components to the request.
Parameters
- member_id (
int): The member's id. - type (
aiobungie.MembershipType): A valid membership type. - components (
list[aiobungie.ComponentType]): List of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will beNone
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
390 async def fetch_linked_profiles( 391 self, 392 member_id: int, 393 member_type: typedefs.IntAnd[enums.MembershipType], 394 /, 395 *, 396 all: bool = False, 397 ) -> profile.LinkedProfile: 398 """Returns a summary information about all profiles linked to the requested member. 399 400 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 401 402 .. note:: 403 It will only return linked accounts whose linkages you are allowed to view. 404 405 Parameters 406 ---------- 407 member_id : `int` 408 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 409 member_type : `aiobungie.MembershipType` 410 The type for the membership whose linked Destiny account you want to return. 411 412 Other Parameters 413 ---------------- 414 all : `bool` 415 If provided and set to `True`, All memberships regardless 416 of whether they're obscured by overrides will be returned, 417 418 If provided and set to `False`, Only available memberships will be returned. 419 The default for this is `False`. 420 421 Returns 422 ------- 423 `aiobungie.crates.profile.LinkedProfile` 424 A linked profile object. 425 """ 426 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 427 428 return self.factory.deserialize_linked_profiles(resp)
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether they're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.crates.profile.LinkedProfile: A linked profile object.
430 async def fetch_player( 431 self, 432 name: str, 433 code: int, 434 /, 435 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 436 ) -> collections.Sequence[user.DestinyMembership]: 437 """Fetch a Destiny 2 player's memberships. 438 439 Parameters 440 ----------- 441 name: `str` 442 The unique Bungie player name. 443 code : `int` 444 The unique Bungie display name code. 445 type: `aiobungie.internal.enums.MembershipType` 446 The player's membership type, e,g. XBOX, STEAM, PSN 447 448 Returns 449 -------- 450 `collections.Sequence[aiobungie.crates.DestinyMembership]` 451 A sequence of the found Destiny 2 player memberships. 452 An empty sequence will be returned if no one found. 453 454 Raises 455 ------ 456 `aiobungie.MembershipTypeError` 457 The provided membership type was invalid. 458 """ 459 resp = await self.rest.fetch_player(name, code, type) 460 461 return self.factory.deserialize_destiny_memberships(resp)
Fetch a Destiny 2 player's memberships.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
collections.Sequence[aiobungie.crates.DestinyMembership]: A sequence of the found Destiny 2 player memberships. An empty sequence will be returned if no one found.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
463 async def fetch_character( 464 self, 465 member_id: int, 466 membership_type: typedefs.IntAnd[enums.MembershipType], 467 character_id: int, 468 components: list[enums.ComponentType], 469 auth: typing.Optional[str] = None, 470 ) -> components.CharacterComponent: 471 """Fetch a Destiny 2 character. 472 473 Parameters 474 ---------- 475 member_id: `int` 476 A valid bungie member id. 477 character_id: `int` 478 The Destiny character id to retrieve. 479 membership_type: `aiobungie.internal.enums.MembershipType` 480 The member's membership type. 481 components: `list[aiobungie.ComponentType]` 482 Multiple arguments of character components to collect and return. 483 484 Other Parameters 485 ---------------- 486 auth : `typing.Optional[str]` 487 A Bearer access_token to make the request with. 488 This is optional and limited to components that only requires an Authorization token. 489 490 Returns 491 ------- 492 `aiobungie.crates.CharacterComponent` 493 A Bungie character component. 494 495 `aiobungie.MembershipTypeError` 496 The provided membership type was invalid. 497 """ 498 resp = await self.rest.fetch_character( 499 member_id, membership_type, character_id, components, auth 500 ) 501 502 return self.factory.deserialize_character_component(resp)
Fetch a Destiny 2 character.
Parameters
- member_id (
int): A valid bungie member id. - character_id (
int): The Destiny character id to retrieve. - membership_type (
aiobungie.MembershipType): The member's membership type. - components (
list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.CharacterComponent: A Bungie character component.aiobungie.MembershipTypeError: The provided membership type was invalid.
504 async def fetch_unique_weapon_history( 505 self, 506 membership_id: int, 507 character_id: int, 508 membership_type: typedefs.IntAnd[enums.MembershipType], 509 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 510 """Fetch details about unique weapon usage for a character. Includes all exotics. 511 512 Parameters 513 ---------- 514 membership_id : `int` 515 The Destiny user membership id. 516 character_id : `int` 517 The character id to retrieve. 518 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 519 The Destiny user's membership type. 520 521 Returns 522 ------- 523 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 524 A sequence of the weapon's extended values. 525 """ 526 resp = await self._rest.fetch_unique_weapon_history( 527 membership_id, character_id, membership_type 528 ) 529 530 return [ 531 self._factory.deserialize_extended_weapon_values(weapon) 532 for weapon in resp["weapons"] 533 ]
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
collections.Sequence[aiobungie.crates.ExtendedWeaponValues]: A sequence of the weapon's extended values.
537 async def fetch_activities( 538 self, 539 member_id: int, 540 character_id: int, 541 mode: typedefs.IntAnd[enums.GameMode], 542 *, 543 membership_type: typedefs.IntAnd[ 544 enums.MembershipType 545 ] = enums.MembershipType.ALL, 546 page: int = 0, 547 limit: int = 250, 548 ) -> iterators.FlatIterator[activity.Activity]: 549 """Fetch a Destiny 2 activity for the specified character id. 550 551 Parameters 552 ---------- 553 member_id: `int` 554 The user id that starts with `4611`. 555 character_id: `int` 556 The id of the character to retrieve the activities for. 557 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 558 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 559 560 Other Parameters 561 ---------------- 562 membership_type: `aiobungie.internal.enums.MembershipType` 563 The Member ship type, if nothing was passed than it will return all. 564 page: int 565 The page number. Default is `0` 566 limit: int 567 Limit the returned result. Default is `250`. 568 569 Returns 570 ------- 571 `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]` 572 An iterator of the player's activities. 573 574 Raises 575 ------ 576 `aiobungie.MembershipTypeError` 577 The provided membership type was invalid. 578 """ 579 resp = await self.rest.fetch_activities( 580 member_id, 581 character_id, 582 mode, 583 membership_type=membership_type, 584 page=page, 585 limit=limit, 586 ) 587 588 return self.factory.deserialize_activities(resp)
Fetch a Destiny 2 activity for the specified character id.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve the activities for. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.MembershipType): The Member ship type, if nothing was passed than it will return all. - page (int):
The page number. Default is
0 - limit (int):
Limit the returned result. Default is
250.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
590 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 591 """Fetch a post activity details. 592 593 Parameters 594 ---------- 595 instance_id: `int` 596 The activity instance id. 597 598 Returns 599 ------- 600 `aiobungie.crates.PostActivity` 601 A post activity object. 602 """ 603 resp = await self.rest.fetch_post_activity(instance_id) 604 605 return self.factory.deserialize_post_activity(resp)
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.crates.PostActivity: A post activity object.
607 async def fetch_aggregated_activity_stats( 608 self, 609 character_id: int, 610 membership_id: int, 611 membership_type: typedefs.IntAnd[enums.MembershipType], 612 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 613 """Fetch aggregated activity stats for a character. 614 615 Parameters 616 ---------- 617 character_id: `int` 618 The id of the character to retrieve the activities for. 619 membership_id: `int` 620 The id of the user that started with `4611`. 621 membership_type: `aiobungie.internal.enums.MembershipType` 622 The Member ship type. 623 624 Returns 625 ------- 626 `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]` 627 An iterator of the player's activities. 628 629 Raises 630 ------ 631 `aiobungie.MembershipTypeError` 632 The provided membership type was invalid. 633 """ 634 resp = await self.rest.fetch_aggregated_activity_stats( 635 character_id, membership_id, membership_type 636 ) 637 638 return self.factory.deserialize_aggregated_activities(resp)
Fetch aggregated activity stats for a character.
Parameters
- character_id (
int): The id of the character to retrieve the activities for. - membership_id (
int): The id of the user that started with4611. - membership_type (
aiobungie.MembershipType): The Member ship type.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
642 async def fetch_clan_from_id( 643 self, 644 id: int, 645 /, 646 access_token: typing.Optional[str] = None, 647 ) -> clans.Clan: 648 """Fetch a Bungie Clan by its id. 649 650 Parameters 651 ----------- 652 id: `int` 653 The clan id. 654 655 Returns 656 -------- 657 `aiobungie.crates.Clan` 658 An Bungie clan. 659 660 Raises 661 ------ 662 `aiobungie.NotFound` 663 The clan was not found. 664 """ 665 resp = await self.rest.fetch_clan_from_id(id, access_token) 666 667 return self.factory.deserialize_clan(resp)
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Returns
aiobungie.crates.Clan: An Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
669 async def fetch_clan( 670 self, 671 name: str, 672 /, 673 access_token: typing.Optional[str] = None, 674 *, 675 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 676 ) -> clans.Clan: 677 """Fetch a Clan by its name. 678 This method will return the first clan found with given name. 679 680 Parameters 681 ---------- 682 name: `str` 683 The clan name 684 685 Other Parameters 686 ---------------- 687 access_token : `typing.Optional[str]` 688 An optional access token to make the request with. 689 690 If the token was bound to a member of the clan, 691 This field `aiobungie.crates.Clan.current_user_membership` will be available 692 and will return the membership of the user who made this request. 693 type : `aiobungie.GroupType` 694 The group type, Default is aiobungie.GroupType.CLAN. 695 696 Returns 697 ------- 698 `aiobungie.crates.Clan` 699 A Bungie clan. 700 701 Raises 702 ------ 703 `aiobungie.NotFound` 704 The clan was not found. 705 """ 706 resp = await self.rest.fetch_clan(name, access_token, type=type) 707 708 return self.factory.deserialize_clan(resp)
Fetch a Clan by its name. This method will return the first clan found with given name.
Parameters
- name (
str): The clan name
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.GroupType): The group type, Default is aiobungie.GroupType.CLAN.
Returns
aiobungie.crates.Clan: A Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
710 async def fetch_clan_conversations( 711 self, clan_id: int, / 712 ) -> collections.Sequence[clans.ClanConversation]: 713 """Fetch the conversations/chat channels of the given clan id. 714 715 Parameters 716 ---------- 717 clan_id : `int` 718 The clan id. 719 720 Returns 721 `collections.Sequence[aiobungie.crates.ClanConversation]` 722 A sequence of the clan chat channels. 723 """ 724 resp = await self.rest.fetch_clan_conversations(clan_id) 725 726 return self.factory.deserialize_clan_conversations(resp)
Fetch the conversations/chat channels of the given clan id.
Parameters
- clan_id (
int): The clan id. - Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of the clan chat channels.
728 async def fetch_clan_admins( 729 self, clan_id: int, / 730 ) -> iterators.FlatIterator[clans.ClanMember]: 731 """Fetch the clan founder and admins. 732 733 Parameters 734 ---------- 735 clan_id : `int` 736 The clan id. 737 738 Returns 739 ------- 740 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 741 An iterator over the found clan admins and founder. 742 743 Raises 744 ------ 745 `aiobungie.NotFound` 746 The requested clan was not found. 747 """ 748 resp = await self.rest.fetch_clan_admins(clan_id) 749 750 return self.factory.deserialize_clan_members(resp)
Fetch the clan founder and admins.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator over the found clan admins and founder.
Raises
aiobungie.NotFound: The requested clan was not found.
752 async def fetch_groups_for_member( 753 self, 754 member_id: int, 755 member_type: typedefs.IntAnd[enums.MembershipType], 756 /, 757 *, 758 filter: int = 0, 759 group_type: enums.GroupType = enums.GroupType.CLAN, 760 ) -> collections.Sequence[clans.GroupMember]: 761 """Fetch information about the groups that a given member has joined. 762 763 Parameters 764 ---------- 765 member_id : `int` 766 The member's id 767 member_type : `aiobungie.MembershipType` 768 The member's membership type. 769 770 Other Parameters 771 ---------------- 772 filter : `int` 773 Filter apply to list of joined groups. This Default to `0` 774 group_type : `aiobungie.GroupType` 775 The group's type. 776 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 777 778 Returns 779 ------- 780 `collections.Sequence[aiobungie.crates.GroupMember]` 781 A sequence of joined groups for the fetched member. 782 """ 783 resp = await self.rest.fetch_groups_for_member( 784 member_id, member_type, filter=filter, group_type=group_type 785 ) 786 787 return [ 788 self.factory.deserialize_group_member(group) for group in resp["results"] 789 ]
Fetch information about the groups that a given member has joined.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.MembershipType): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.GroupType): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined groups for the fetched member.
791 async def fetch_potential_groups_for_member( 792 self, 793 member_id: int, 794 member_type: typedefs.IntAnd[enums.MembershipType], 795 /, 796 *, 797 filter: int = 0, 798 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 799 ) -> collections.Sequence[clans.GroupMember]: 800 """Fetch the potential groups for a clan member. 801 802 Parameters 803 ---------- 804 member_id : `int` 805 The member's id 806 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 807 The member's membership type. 808 809 Other Parameters 810 ---------------- 811 filter : `int` 812 Filter apply to list of joined groups. This Default to `0` 813 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 814 The group's type. 815 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 816 817 Returns 818 ------- 819 `collections.Sequence[aiobungie.crates.GroupMember]` 820 A sequence of joined potential groups for the fetched member. 821 """ 822 resp = await self.rest.fetch_potential_groups_for_member( 823 member_id, member_type, filter=filter, group_type=group_type 824 ) 825 826 return [ 827 self.factory.deserialize_group_member(group) for group in resp["results"] 828 ]
Fetch the potential groups for a clan member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined potential groups for the fetched member.
830 async def fetch_clan_members( 831 self, 832 clan_id: int, 833 /, 834 *, 835 name: typing.Optional[str] = None, 836 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 837 ) -> iterators.FlatIterator[clans.ClanMember]: 838 """Fetch Bungie clan members. 839 840 Parameters 841 ---------- 842 clan_id : `int` 843 The clans id 844 845 Other Parameters 846 ---------------- 847 name : `typing.Optional[str]` 848 If provided, Only players matching this name will be returned. 849 type : `aiobungie.MembershipType` 850 An optional clan member's membership type. 851 This parameter is used to filter the returned results 852 by the provided membership, For an example XBox memberships only, 853 Otherwise will return all memberships. 854 855 Returns 856 ------- 857 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 858 An iterator over the bungie clan members. 859 860 Raises 861 ------ 862 `aiobungie.NotFound` 863 The clan was not found. 864 """ 865 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 866 867 return self.factory.deserialize_clan_members(resp)
Fetch Bungie clan members.
Parameters
- clan_id (
int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator over the bungie clan members.
Raises
aiobungie.NotFound: The clan was not found.
882 async def kick_clan_member( 883 self, 884 access_token: str, 885 /, 886 group_id: int, 887 membership_id: int, 888 membership_type: typedefs.IntAnd[enums.MembershipType], 889 ) -> clans.Clan: 890 """Kick a member from the clan. 891 892 .. note:: 893 This request requires OAuth2: oauth2: `AdminGroups` scope. 894 895 Parameters 896 ---------- 897 access_token : `str` 898 The bearer access token associated with the bungie account. 899 group_id: `int` 900 The group id. 901 membership_id : `int` 902 The member id to kick. 903 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 904 The member's membership type. 905 906 Returns 907 ------- 908 `aiobungie.crates.clan.Clan` 909 The clan that the member was kicked from. 910 """ 911 resp = await self.rest.kick_clan_member( 912 access_token, 913 group_id=group_id, 914 membership_id=membership_id, 915 membership_type=membership_type, 916 ) 917 918 return self.factory.deserialize_clan(resp)
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.crates.clan.Clan: The clan that the member was kicked from.
920 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 921 """Fetch a Bungie clan's weekly reward state. 922 923 Parameters 924 ---------- 925 clan_id : `int` 926 The clan's id. 927 928 Returns 929 ------- 930 `aiobungie.crates.Milestone` 931 A runtime status of the clan's milestone data. 932 """ 933 934 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 935 936 return self.factory.deserialize_milestone(resp)
Fetch a Bungie clan's weekly reward state.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.crates.Milestone: A runtime status of the clan's milestone data.
940 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 941 """Fetch a static inventory item entity given a its hash. 942 943 Parameters 944 ---------- 945 hash: `int` 946 Inventory item's hash. 947 948 Returns 949 ------- 950 `aiobungie.crates.InventoryEntity` 951 A bungie inventory item. 952 """ 953 resp = await self.rest.fetch_inventory_item(hash) 954 955 return self.factory.deserialize_inventory_entity(resp)
Fetch a static inventory item entity given a its hash.
Parameters
- hash (
int): Inventory item's hash.
Returns
aiobungie.crates.InventoryEntity: A bungie inventory item.
957 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 958 """Fetch a Destiny objective entity given a its hash. 959 960 Parameters 961 ---------- 962 hash: `int` 963 objective's hash. 964 965 Returns 966 ------- 967 `aiobungie.crates.ObjectiveEntity` 968 An objective entity item. 969 """ 970 resp = await self.rest.fetch_objective_entity(hash) 971 972 return self.factory.deserialize_objective_entity(resp)
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity item.
974 async def search_entities( 975 self, name: str, entity_type: str, *, page: int = 0 976 ) -> iterators.FlatIterator[entity.SearchableEntity]: 977 """Search for Destiny2 entities given a name and its type. 978 979 Parameters 980 ---------- 981 name : `str` 982 The name of the entity, i.e., Thunderlord, One thousand voices. 983 entity_type : `str` 984 The type of the entity, AKA Definition, 985 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 986 987 Other Parameters 988 ---------------- 989 page : `int` 990 An optional page to return. Default to 0. 991 992 Returns 993 ------- 994 `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]` 995 An iterator over the found results matching the provided name. 996 """ 997 resp = await self.rest.search_entities(name, entity_type, page=page) 998 999 return self.factory.deserialize_inventory_results(resp)
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinitionfor emblems, weapons, and other inventory items.
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]: An iterator over the found results matching the provided name.
1003 async def fetch_fireteams( 1004 self, 1005 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1006 *, 1007 platform: typedefs.IntAnd[ 1008 fireteams.FireteamPlatform 1009 ] = fireteams.FireteamPlatform.ANY, 1010 language: typing.Union[ 1011 fireteams.FireteamLanguage, str 1012 ] = fireteams.FireteamLanguage.ALL, 1013 date_range: int = 0, 1014 page: int = 0, 1015 slots_filter: int = 0, 1016 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1017 """Fetch public Bungie fireteams with open slots. 1018 1019 Parameters 1020 ---------- 1021 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1022 The fireteam activity type. 1023 1024 Other Parameters 1025 ---------------- 1026 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1027 If this is provided. Then the results will be filtered with the given platform. 1028 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1029 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1030 A locale language to filter the used language in that fireteam. 1031 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1032 date_range : `int` 1033 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1034 page : `int` 1035 The page number. By default its `0` which returns all available activities. 1036 slots_filter : `int` 1037 Filter the returned fireteams based on available slots. Default is `0` 1038 1039 Returns 1040 ------- 1041 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1042 A sequence of `aiobungie.crates.Fireteam` or `None`. 1043 """ 1044 1045 resp = await self.rest.fetch_fireteams( 1046 activity_type, 1047 platform=platform, 1048 language=language, 1049 date_range=date_range, 1050 page=page, 1051 slots_filter=slots_filter, 1052 ) 1053 1054 return self.factory.deserialize_fireteams(resp)
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[fireteams.Fireteam]]: A sequence ofaiobungie.crates.FireteamorNone.
1056 async def fetch_avaliable_clan_fireteams( 1057 self, 1058 access_token: str, 1059 group_id: int, 1060 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1061 *, 1062 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1063 language: typing.Union[fireteams.FireteamLanguage, str], 1064 date_range: int = 0, 1065 page: int = 0, 1066 public_only: bool = False, 1067 slots_filter: int = 0, 1068 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1069 """Fetch a clan's fireteams with open slots. 1070 1071 .. note:: 1072 This method requires OAuth2: ReadGroups scope. 1073 1074 Parameters 1075 ---------- 1076 access_token : `str` 1077 The bearer access token associated with the bungie account. 1078 group_id : `int` 1079 The group/clan id of the fireteam. 1080 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1081 The fireteam activity type. 1082 1083 Other Parameters 1084 ---------------- 1085 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1086 If this is provided. Then the results will be filtered with the given platform. 1087 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1088 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1089 A locale language to filter the used language in that fireteam. 1090 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1091 date_range : `int` 1092 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1093 page : `int` 1094 The page number. By default its `0` which returns all available activities. 1095 public_only: `bool` 1096 If set to True, Then only public fireteams will be returned. 1097 slots_filter : `int` 1098 Filter the returned fireteams based on available slots. Default is `0` 1099 1100 Returns 1101 ------- 1102 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1103 A sequence of fireteams found in the clan. 1104 `None` will be returned if nothing was found. 1105 """ 1106 resp = await self.rest.fetch_avaliable_clan_fireteams( 1107 access_token, 1108 group_id, 1109 activity_type, 1110 platform=platform, 1111 language=language, 1112 date_range=date_range, 1113 page=page, 1114 public_only=public_only, 1115 slots_filter=slots_filter, 1116 ) 1117 1118 return self.factory.deserialize_fireteams(resp)
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults to0. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan.Nonewill be returned if nothing was found.
1120 async def fetch_clan_fireteam( 1121 self, access_token: str, fireteam_id: int, group_id: int 1122 ) -> fireteams.AvailableFireteam: 1123 """Fetch a specific clan fireteam. 1124 1125 .. note:: 1126 This method requires OAuth2: ReadGroups scope. 1127 1128 Parameters 1129 ---------- 1130 access_token : `str` 1131 The bearer access token associated with the bungie account. 1132 group_id : `int` 1133 The group/clan id to fetch the fireteam from. 1134 fireteam_id : `int` 1135 The fireteam id to fetch. 1136 1137 Returns 1138 ------- 1139 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1140 A sequence of available fireteams objects if exists. else `None` will be returned. 1141 """ 1142 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1143 1144 return self.factory.deserialize_available_fireteams( 1145 resp, no_results=True 1146 ) # type: ignore[return-value]
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
typing.Optional[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1148 async def fetch_my_clan_fireteams( 1149 self, 1150 access_token: str, 1151 group_id: int, 1152 *, 1153 include_closed: bool = True, 1154 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1155 language: typing.Union[fireteams.FireteamLanguage, str], 1156 filtered: bool = True, 1157 page: int = 0, 1158 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1159 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1160 1161 .. note:: 1162 This method requires OAuth2: ReadGroups scope. 1163 1164 Parameters 1165 ---------- 1166 access_token : str 1167 The bearer access token associated with the bungie account. 1168 group_id : int 1169 The group/clan id to fetch. 1170 1171 Other Parameters 1172 ---------------- 1173 include_closed : bool 1174 If provided and set to True, It will also return closed fireteams. 1175 If provided and set to False, It will only return public fireteams. Default is True. 1176 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1177 If this is provided. Then the results will be filtered with the given platform. 1178 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1179 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1180 A locale language to filter the used language in that fireteam. 1181 Defaults to aiobungie.crates.FireteamLanguage.ALL 1182 filtered : bool 1183 If set to True, it will filter by clan. Otherwise not. Default is True. 1184 page : int 1185 The page number. By default its 0 which returns all available activities. 1186 1187 Returns 1188 ------- 1189 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1190 A sequence of available fireteams objects if exists. else `None` will be returned. 1191 """ 1192 resp = await self.rest.fetch_my_clan_fireteams( 1193 access_token, 1194 group_id, 1195 include_closed=include_closed, 1196 platform=platform, 1197 language=language, 1198 filtered=filtered, 1199 page=page, 1200 ) 1201 1202 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value]
A method that's similar to fetch_fireteams but requires OAuth2.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (str): The bearer access token associated with the bungie account.
- group_id (int): The group/clan id to fetch.
Other Parameters
- include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
- platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
- language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
- filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
- page (int): The page number. By default its 0 which returns all available activities.
Returns
collections.Sequence[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1206 async def fetch_friends( 1207 self, access_token: str, / 1208 ) -> collections.Sequence[friends.Friend]: 1209 """Fetch bungie friend list. 1210 1211 .. note:: 1212 This requests OAuth2: ReadUserData scope. 1213 1214 Parameters 1215 ----------- 1216 access_token : `str` 1217 The bearer access token associated with the bungie account. 1218 1219 Returns 1220 ------- 1221 `collections.Sequence[aiobungie.crates.Friend]` 1222 A sequence of the friends associated with that access token. 1223 """ 1224 1225 resp = await self.rest.fetch_friends(access_token) 1226 1227 return self.factory.deserialize_friends(resp)
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of the friends associated with that access token.
1229 async def fetch_friend_requests( 1230 self, access_token: str, / 1231 ) -> friends.FriendRequestView: 1232 """Fetch pending bungie friend requests queue. 1233 1234 .. note:: 1235 This requests OAuth2: ReadUserData scope. 1236 1237 Parameters 1238 ----------- 1239 access_token : `str` 1240 The bearer access token associated with the bungie account. 1241 1242 Returns 1243 ------- 1244 `aiobungie.crates.FriendRequestView` 1245 A friend requests view of that associated access token. 1246 """ 1247 1248 resp = await self.rest.fetch_friend_requests(access_token) 1249 1250 return self.factory.deserialize_friend_requests(resp)
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.crates.FriendRequestView: A friend requests view of that associated access token.
1254 async def fetch_application(self, appid: int, /) -> application.Application: 1255 """Fetch a Bungie application. 1256 1257 Parameters 1258 ----------- 1259 appid: `int` 1260 The application id. 1261 1262 Returns 1263 -------- 1264 `aiobungie.crates.Application` 1265 A Bungie application. 1266 """ 1267 resp = await self.rest.fetch_application(appid) 1268 1269 return self.factory.deserialize_app(resp)
Fetch a Bungie application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.crates.Application: A Bungie application.
1273 async def fetch_public_milestone_content( 1274 self, milestone_hash: int, / 1275 ) -> milestones.MilestoneContent: 1276 """Fetch the milestone content given its hash. 1277 1278 Parameters 1279 ---------- 1280 milestone_hash : `int` 1281 The milestone hash. 1282 1283 Returns 1284 ------- 1285 `aiobungie.crates.milestones.MilestoneContent` 1286 A milestone content object. 1287 """ 1288 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1289 1290 return self.factory.deserialize_public_milestone_content(resp)
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.crates.milestones.MilestoneContent: A milestone content object.
782@typing.final 783class ClosedReasons(Flag): 784 """A Flags enumeration representing the reasons why a person can't join this user's fireteam.""" 785 786 NONE = 0 787 MATCHMAKING = 1 788 LOADING = 2 789 SOLO = 4 790 """The activity is required to be played solo.""" 791 INTERNAL_REASONS = 8 792 """ 793 The user can't be joined for one of a variety of internal reasons. 794 Basically, the game can't let you join at this time, 795 but for reasons that aren't under the control of this user 796 """ 797 DISALLOWED_BY_GAME_STATE = 16 798 """The user's current activity/quest/other transitory game state is preventing joining.""" 799 OFFLINE = 32768 800 """The user appears offline."""
A Flags enumeration representing the reasons why a person can't join this user's fireteam.
The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user
The user's current activity/quest/other transitory game state is preventing joining.
74@typing.final 75class ComponentFields(enums.Enum): 76 """An enum that provides fields found in a base component response.""" 77 78 PRIVACY = ComponentPrivacy 79 DISABLED = False
An enum that provides fields found in a base component response.
65@typing.final 66class ComponentPrivacy(int, enums.Enum): 67 """An enum the provides privacy settings for profile components.""" 68 69 NONE = 0 70 PUBLIC = 1 71 PRIVATE = 2
An enum the provides privacy settings for profile components.
363@typing.final 364class ComponentType(Enum): 365 """An Enum for Destiny 2 profile Components.""" 366 367 NONE = 0 368 369 PROFILE = 100 370 PROFILE_INVENTORIES = 102 371 PROFILE_CURRENCIES = 103 372 PROFILE_PROGRESSION = 104 373 ALL_PROFILES = ( 374 PROFILE, 375 PROFILE_INVENTORIES, 376 PROFILE_CURRENCIES, 377 PROFILE_PROGRESSION, 378 ) 379 """All profile components.""" 380 381 VENDORS = 400 382 VENDOR_SALES = 402 383 VENDOR_RECEIPTS = 101 384 ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES) 385 """All vendor components.""" 386 387 # Items 388 ITEM_INSTANCES = 300 389 ITEM_OBJECTIVES = 301 390 ITEM_PERKS = 302 391 ITEM_RENDER_DATA = 303 392 ITEM_STATS = 304 393 ITEM_SOCKETS = 305 394 ITEM_TALENT_GRINDS = 306 395 ITEM_PLUG_STATES = 308 396 ITEM_PLUG_OBJECTIVES = 309 397 ITEM_REUSABLE_PLUGS = 310 398 399 ALL_ITEMS = ( 400 ITEM_PLUG_OBJECTIVES, 401 ITEM_PLUG_STATES, 402 ITEM_SOCKETS, 403 ITEM_INSTANCES, 404 ITEM_OBJECTIVES, 405 ITEM_PERKS, 406 ITEM_RENDER_DATA, 407 ITEM_STATS, 408 ITEM_TALENT_GRINDS, 409 ITEM_REUSABLE_PLUGS, 410 ) 411 """All item components.""" 412 413 PLATFORM_SILVER = 105 414 KIOSKS = 500 415 CURRENCY_LOOKUPS = 600 416 PRESENTATION_NODES = 700 417 COLLECTIBLES = 800 418 RECORDS = 900 419 TRANSITORY = 1000 420 METRICS = 1100 421 INVENTORIES = 102 422 STRING_VARIABLES = 1200 423 CRAFTABLES = 1300 424 425 CHARACTERS = 200 426 CHARACTER_INVENTORY = 201 427 CHARECTER_PROGRESSION = 202 428 CHARACTER_RENDER_DATA = 203 429 CHARACTER_ACTIVITIES = 204 430 CHARACTER_EQUIPMENT = 205 431 432 ALL_CHARACTERS = ( 433 CHARACTERS, 434 CHARACTER_INVENTORY, 435 CHARECTER_PROGRESSION, 436 CHARACTER_RENDER_DATA, 437 CHARACTER_ACTIVITIES, 438 CHARACTER_EQUIPMENT, 439 RECORDS, 440 ) 441 """All character components.""" 442 443 ALL = ( 444 *ALL_PROFILES, # type: ignore 445 *ALL_CHARACTERS, # type: ignore 446 *ALL_VENDORS, # type: ignore 447 *ALL_ITEMS, # type: ignore 448 RECORDS, 449 CURRENCY_LOOKUPS, 450 PRESENTATION_NODES, 451 COLLECTIBLES, 452 KIOSKS, 453 METRICS, 454 PLATFORM_SILVER, 455 INVENTORIES, 456 STRING_VARIABLES, 457 TRANSITORY, 458 CRAFTABLES, 459 ) 460 """ALl components included."""
An Enum for Destiny 2 profile Components.
All item components.
All character components.
ALl components included.
664@typing.final 665class CredentialType(int, Enum): 666 """The types of the accounts system supports at bungie.""" 667 668 NONE = 0 669 XUID = 1 670 PSNID = 2 671 WILD = 3 672 FAKE = 4 673 FACEBOOK = 5 674 GOOGLE = 8 675 WINDOWS = 9 676 DEMONID = 10 677 STEAMID = 12 678 BATTLENETID = 14 679 STADIAID = 16 680 TWITCHID = 18
The types of the accounts system supports at bungie.
542@typing.final 543class DamageType(int, Enum): 544 """Enums for Destiny Damage types""" 545 546 NONE = 0 547 KINETIC = 1 548 ARC = 2 549 SOLAR = 3 550 VOID = 4 551 RAID = 5 552 """This is a special damage type reserved for some raid activity encounters.""" 553 STASIS = 6
Enums for Destiny Damage types
This is a special damage type reserved for some raid activity encounters.
65@typing.final 66class Difficulty(int, enums.Enum): 67 """An enum for activities difficulties.""" 68 69 TRIVIAL = 0 70 EASY = 1 71 NORMAL = 2 72 CHALLENGING = 3 73 HARD = 4 74 BRAVE = 5 75 ALMOST_IMPOSSIBLE = 6 76 IMPOSSIBLE = 7
An enum for activities difficulties.
165@typing.final 166class Dungeon(int, Enum): 167 """An Enum for all available Dungeon/Like missions in Destiny 2.""" 168 169 NORMAL_PRESAGE = 2124066889 170 """Normal Presage""" 171 172 MASTER_PRESAGE = 4212753278 173 """Master Presage""" 174 175 HARBINGER = 1738383283 176 """Harbinger""" 177 178 PROPHECY = 4148187374 179 """Prophecy""" 180 181 MASTER_POH = 785700673 182 """Master Pit of Heresy?""" 183 184 LEGEND_POH = 785700678 185 """Legend Pit of Heresy?""" 186 187 POH = 1375089621 188 """Normal Pit of Heresy.""" 189 190 SHATTERED = 2032534090 191 """Shattered Throne""" 192 193 GOA_LEGEND = 4078656646 194 """Grasp of Avarice legend.""" 195 196 GOA_MASTER = 3774021532 197 """Grasp of Avarice master."""
An Enum for all available Dungeon/Like missions in Destiny 2.
77class Enum(__enum.Enum): 78 """Builtin Python enum with extra handlings.""" 79 80 @property 81 def name(self) -> str: # type: ignore[override] 82 return self._name_ 83 84 @property 85 def value(self) -> typing.Any: # type: ignore[override] 86 return self._value_ 87 88 def __str__(self) -> str: 89 return self._name_ 90 91 def __repr__(self) -> str: 92 return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>" 93 94 def __int__(self) -> int: 95 if isinstance(self.value, _ITERABLE): 96 raise TypeError( 97 f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.", 98 ) 99 return int(self.value)
Builtin Python enum with extra handlings.
61class Factory(interfaces.FactoryInterface): 62 """The base deserialization factory class for all aiobungie objects. 63 64 Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them 65 into a `aiobungie.crates` Python classes. 66 """ 67 68 __slots__ = ("_net",) 69 70 def __init__(self, net: traits.Netrunner) -> None: 71 self._net = net 72 73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 ) 96 97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.Undefined), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 ) 113 114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.Undefined 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") # noqa: W503 130 or "", # noqa: W503 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload.get("applicableMembershipTypes", []) 138 ], 139 ) 140 141 def deserialize_destiny_memberships( 142 self, data: typedefs.JSONArray 143 ) -> collections.Sequence[user.DestinyMembership]: 144 return [self.deserialize_destiny_membership(membership) for membership in data] 145 146 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 147 148 primary_membership_id: typing.Optional[int] = None 149 if raw_primary_id := data.get("primaryMembershipId"): 150 primary_membership_id = int(raw_primary_id) 151 152 return user.User( 153 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 154 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 155 primary_membership_id=primary_membership_id, 156 ) 157 158 def deserialize_searched_user( 159 self, payload: typedefs.JSONObject 160 ) -> user.SearchableDestinyUser: 161 name: undefined.UndefinedOr[str] = undefined.Undefined 162 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 163 raw_name 164 ): 165 name = raw_name 166 167 code: typing.Optional[int] = None 168 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 169 code = int(raw_code) 170 171 bungie_id: typing.Optional[int] = None 172 if raw_bungie_id := payload.get("bungieNetMembershipId"): 173 bungie_id = int(raw_bungie_id) 174 175 return user.SearchableDestinyUser( 176 name=name, 177 code=code, 178 bungie_id=bungie_id, 179 memberships=self.deserialize_destiny_memberships( 180 payload["destinyMemberships"] 181 ), 182 ) 183 184 def deserialize_user_credentials( 185 self, payload: typedefs.JSONArray 186 ) -> collections.Sequence[user.UserCredentials]: 187 return [ 188 user.UserCredentials( 189 type=enums.CredentialType(int(creds["credentialType"])), 190 display_name=creds["credentialDisplayName"], 191 is_public=creds["isPublic"], 192 self_as_string=creds.get("credentialAsString", undefined.Undefined), 193 ) 194 for creds in payload 195 ] 196 197 @staticmethod 198 def set_themese_attrs( 199 payload: typedefs.JSONArray, / 200 ) -> typing.Collection[user.UserThemes]: 201 return [ 202 user.UserThemes( 203 id=int(entry["userThemeId"]), 204 name=entry["userThemeName"] 205 if "userThemeName" in entry 206 else undefined.Undefined, 207 description=entry["userThemeDescription"] 208 if "userThemeDescription" in entry 209 else undefined.Undefined, 210 ) 211 for entry in payload 212 ] 213 214 def deserialize_user_themes( 215 self, payload: typedefs.JSONArray 216 ) -> collections.Sequence[user.UserThemes]: 217 return list(self.set_themese_attrs(payload)) 218 219 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 220 221 # This is kinda redundant 222 data = payload 223 224 # This is always outside the details. 225 current_user_map: typing.Optional[ 226 collections.Mapping[str, clans.ClanMember] 227 ] = None 228 if raw_current_user_map := payload.get("currentUserMemberMap"): 229 current_user_map = { 230 membership_type: self.deserialize_clan_member(membership) 231 for membership_type, membership in raw_current_user_map.items() 232 } 233 234 try: 235 data = payload["detail"] 236 except KeyError: 237 pass 238 239 id = data["groupId"] 240 name = data["name"] 241 created_at = data["creationDate"] 242 member_count = data["memberCount"] 243 about = data["about"] 244 motto = data["motto"] 245 is_public = data["isPublic"] 246 banner = assets.Image(str(data["bannerPath"])) 247 avatar = assets.Image(str(data["avatarPath"])) 248 tags = data["tags"] 249 type = data["groupType"] 250 251 features = data["features"] 252 features_obj = clans.ClanFeatures( 253 max_members=features["maximumMembers"], 254 max_membership_types=features["maximumMembershipsOfGroupType"], 255 capabilities=features["capabilities"], 256 membership_types=features["membershipTypes"], 257 invite_permissions=features["invitePermissionOverride"], 258 update_banner_permissions=features["updateBannerPermissionOverride"], 259 update_culture_permissions=features["updateCulturePermissionOverride"], 260 join_level=features["joinLevel"], 261 ) 262 263 information: typedefs.JSONObject = data["clanInfo"] 264 progression: collections.Mapping[int, progressions.Progression] = { 265 int(prog_hash): self.deserialize_progressions(prog) 266 for prog_hash, prog in information["d2ClanProgressions"].items() 267 } 268 269 founder: typedefs.NoneOr[clans.ClanMember] = None 270 if raw_founder := payload.get("founder"): 271 founder = self.deserialize_clan_member(raw_founder) 272 273 return clans.Clan( 274 net=self._net, 275 id=int(id), 276 name=name, 277 type=enums.GroupType(type), 278 created_at=time.clean_date(created_at), 279 member_count=member_count, 280 motto=motto, 281 about=about, 282 is_public=is_public, 283 banner=banner, 284 avatar=avatar, 285 tags=tags, 286 features=features_obj, 287 owner=founder, 288 progressions=progression, 289 call_sign=information["clanCallsign"], 290 banner_data=information["clanBannerData"], 291 chat_security=data["chatSecurity"], 292 conversation_id=int(data["conversationId"]), 293 allow_chat=data["allowChat"], 294 theme=data["theme"], 295 current_user_membership=current_user_map, 296 ) 297 298 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 299 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 300 return clans.ClanMember( 301 net=self._net, 302 last_seen_name=destiny_user.last_seen_name, 303 id=destiny_user.id, 304 name=destiny_user.name, 305 icon=destiny_user.icon, 306 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 307 group_id=int(data["groupId"]), 308 joined_at=time.clean_date(data["joinDate"]), 309 types=destiny_user.types, 310 is_public=destiny_user.is_public, 311 type=destiny_user.type, 312 code=destiny_user.code, 313 is_online=data["isOnline"], 314 crossave_override=destiny_user.crossave_override, 315 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 316 if "bungieNetUserInfo" in data 317 else None, 318 member_type=enums.ClanMemberType(int(data["memberType"])), 319 ) 320 321 def deserialize_clan_members( 322 self, data: typedefs.JSONObject, / 323 ) -> iterators.FlatIterator[clans.ClanMember]: 324 return iterators.FlatIterator( 325 [self.deserialize_clan_member(member) for member in data["results"]] 326 ) 327 328 def deserialize_group_member( 329 self, payload: typedefs.JSONObject 330 ) -> clans.GroupMember: 331 member = payload["member"] 332 return clans.GroupMember( 333 net=self._net, 334 join_date=time.clean_date(member["joinDate"]), 335 group_id=int(member["groupId"]), 336 member_type=enums.ClanMemberType(member["memberType"]), 337 is_online=member["isOnline"], 338 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 339 inactive_memberships=payload.get("areAllMembershipsInactive", None), 340 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 341 group=self.deserialize_clan(payload["group"]), 342 ) 343 344 def _deserialize_clan_conversation( 345 self, payload: typedefs.JSONObject 346 ) -> clans.ClanConversation: 347 return clans.ClanConversation( 348 net=self._net, 349 id=int(payload["conversationId"]), 350 group_id=int(payload["groupId"]), 351 name=( 352 payload["chatName"] 353 if not typedefs.is_unknown(payload["chatName"]) 354 else undefined.Undefined 355 ), 356 chat_enabled=payload["chatEnabled"], 357 security=payload["chatSecurity"], 358 ) 359 360 def deserialize_clan_conversations( 361 self, payload: typedefs.JSONArray 362 ) -> collections.Sequence[clans.ClanConversation]: 363 return [self._deserialize_clan_conversation(conv) for conv in payload] 364 365 def deserialize_app_owner( 366 self, payload: typedefs.JSONObject 367 ) -> application.ApplicationOwner: 368 return application.ApplicationOwner( 369 net=self._net, 370 name=payload.get("bungieGlobalDisplayName", undefined.Undefined), 371 id=int(payload["membershipId"]), 372 type=enums.MembershipType(payload["membershipType"]), 373 icon=assets.Image(str(payload["iconPath"])), 374 is_public=payload["isPublic"], 375 code=payload.get("bungieGlobalDisplayNameCode", None), 376 ) 377 378 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 379 return application.Application( 380 id=int(payload["applicationId"]), 381 name=payload["name"], 382 link=payload["link"], 383 status=payload["status"], 384 redirect_url=payload.get("redirectUrl", None), 385 created_at=time.clean_date(str(payload["creationDate"])), 386 published_at=time.clean_date(str(payload["firstPublished"])), 387 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 388 scope=payload.get("scope", undefined.Undefined), 389 ) 390 391 def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character: 392 total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True) 393 return character.Character( 394 net=self._net, 395 id=int(payload["characterId"]), 396 gender=enums.Gender(payload["genderType"]), 397 race=enums.Race(payload["raceType"]), 398 class_type=enums.Class(payload["classType"]), 399 emblem=assets.Image(str(payload["emblemBackgroundPath"])), 400 emblem_icon=assets.Image(str(payload["emblemPath"])), 401 emblem_hash=int(payload["emblemHash"]), 402 last_played=time.clean_date(payload["dateLastPlayed"]), 403 total_played_time=total_time, 404 member_id=int(payload["membershipId"]), 405 member_type=enums.MembershipType(payload["membershipType"]), 406 level=payload["baseCharacterLevel"], 407 title_hash=payload.get("titleRecordHash", None), 408 light=payload["light"], 409 stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()}, 410 ) 411 412 def deserialize_profile( 413 self, payload: typedefs.JSONObject, / 414 ) -> typing.Optional[profile.Profile]: 415 if (raw_profile := payload.get("data")) is None: 416 return None 417 418 payload = raw_profile 419 id = int(payload["userInfo"]["membershipId"]) 420 name = payload["userInfo"]["displayName"] 421 is_public = payload["userInfo"]["isPublic"] 422 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 423 last_played = time.clean_date(str(payload["dateLastPlayed"])) 424 character_ids = [int(cid) for cid in payload["characterIds"]] 425 power_cap = payload["currentSeasonRewardPowerCap"] 426 427 return profile.Profile( 428 id=int(id), 429 name=name, 430 is_public=is_public, 431 type=type, 432 last_played=last_played, 433 character_ids=character_ids, 434 power_cap=power_cap, 435 net=self._net, 436 ) 437 438 def deserialize_profile_item( 439 self, payload: typedefs.JSONObject 440 ) -> profile.ProfileItemImpl: 441 442 instance_id: typing.Optional[int] = None 443 if raw_instance_id := payload.get("itemInstanceId"): 444 instance_id = int(raw_instance_id) 445 446 version_number: typing.Optional[int] = None 447 if raw_version := payload.get("versionNumber"): 448 version_number = int(raw_version) 449 450 transfer_status = enums.TransferStatus(payload["transferStatus"]) 451 452 return profile.ProfileItemImpl( 453 net=self._net, 454 hash=payload["itemHash"], 455 quantity=payload["quantity"], 456 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 457 location=enums.ItemLocation(payload["location"]), 458 bucket=payload["bucketHash"], 459 transfer_status=transfer_status, 460 lockable=payload["lockable"], 461 state=enums.ItemState(payload["state"]), 462 dismantel_permissions=payload["dismantlePermission"], 463 is_wrapper=payload["isWrapper"], 464 instance_id=instance_id, 465 version_number=version_number, 466 ornament_id=payload.get("overrideStyleItemHash"), 467 ) 468 469 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 470 return records.Objective( 471 net=self._net, 472 hash=payload["objectiveHash"], 473 visible=payload["visible"], 474 complete=payload["complete"], 475 completion_value=payload["completionValue"], 476 progress=payload.get("progress"), 477 destination_hash=payload.get("destinationHash"), 478 activity_hash=payload.get("activityHash"), 479 ) 480 481 def deserialize_records( 482 self, 483 payload: typedefs.JSONObject, 484 scores: typing.Optional[records.RecordScores] = None, 485 **nodes: int, 486 ) -> records.Record: 487 objectives: typing.Optional[list[records.Objective]] = None 488 interval_objectives: typing.Optional[list[records.Objective]] = None 489 record_state: typedefs.IntAnd[records.RecordState] 490 491 record_state = records.RecordState(payload["state"]) 492 493 if raw_objs := payload.get("objectives"): 494 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 495 496 if raw_interval_objs := payload.get("intervalObjectives"): 497 interval_objectives = [ 498 self.deserialize_objectives(obj) for obj in raw_interval_objs 499 ] 500 501 return records.Record( 502 scores=scores, 503 categories_node_hash=nodes.get("categories_hash", undefined.Undefined), 504 seals_node_hash=nodes.get("seals_hash", undefined.Undefined), 505 state=record_state, 506 objectives=objectives, 507 interval_objectives=interval_objectives, 508 redeemed_count=payload.get("intervalsRedeemedCount", 0), 509 completion_times=payload.get("completedCount", None), 510 reward_visibility=payload.get("rewardVisibilty", None), 511 ) 512 513 def deserialize_character_records( 514 self, 515 payload: typedefs.JSONObject, 516 scores: typing.Optional[records.RecordScores] = None, 517 record_hashes: typing.Optional[list[int]] = None, 518 ) -> records.CharacterRecord: 519 520 record = self.deserialize_records(payload, scores) 521 return records.CharacterRecord( 522 scores=scores, 523 categories_node_hash=record.categories_node_hash, 524 seals_node_hash=record.seals_node_hash, 525 state=record.state, 526 objectives=record.objectives, 527 interval_objectives=record.interval_objectives, 528 redeemed_count=payload.get("intervalsRedeemedCount", 0), 529 completion_times=payload.get("completedCount"), 530 reward_visibility=payload.get("rewardVisibilty"), 531 record_hashes=record_hashes or [], 532 ) 533 534 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 535 return character.Dye( 536 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 537 ) 538 539 def deserialize_character_customization( 540 self, payload: typedefs.JSONObject 541 ) -> character.CustomizationOptions: 542 return character.CustomizationOptions( 543 personality=payload["personality"], 544 face=payload["face"], 545 skin_color=payload["skinColor"], 546 lip_color=payload["lipColor"], 547 eye_color=payload["eyeColor"], 548 hair_colors=payload.get("hairColors", []), 549 feature_colors=payload.get("featureColors", []), 550 decal_color=payload["decalColor"], 551 wear_helmet=payload["wearHelmet"], 552 hair_index=payload["hairIndex"], 553 feature_index=payload["featureIndex"], 554 decal_index=payload["decalIndex"], 555 ) 556 557 def deserialize_character_minimal_equipments( 558 self, payload: typedefs.JSONObject 559 ) -> character.MinimalEquipments: 560 dyes = None 561 if raw_dyes := payload.get("dyes"): 562 if raw_dyes: 563 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 564 return character.MinimalEquipments( 565 net=self._net, item_hash=payload["itemHash"], dyes=dyes 566 ) 567 568 def deserialize_character_render_data( 569 self, payload: typedefs.JSONObject, / 570 ) -> character.RenderedData: 571 return character.RenderedData( 572 net=self._net, 573 customization=self.deserialize_character_customization( 574 payload["customization"] 575 ), 576 custom_dyes=[ 577 self.deserialize_character_dye(dye) 578 for dye in payload["customDyes"] 579 if dye 580 ], 581 equipment=[ 582 self.deserialize_character_minimal_equipments(equipment) 583 for equipment in payload["peerView"]["equipment"] 584 ], 585 ) 586 587 def deserialize_available_activity( 588 self, payload: typedefs.JSONObject 589 ) -> activity.AvailableActivity: 590 return activity.AvailableActivity( 591 hash=payload["activityHash"], 592 is_new=payload["isNew"], 593 is_completed=payload["isCompleted"], 594 is_visible=payload["isVisible"], 595 display_level=payload.get("displayLevel"), 596 recommended_light=payload.get("recommendedLight"), 597 difficulty=activity.Difficulty(payload["difficultyTier"]), 598 can_join=payload["canJoin"], 599 can_lead=payload["canLead"], 600 ) 601 602 def deserialize_character_activity( 603 self, payload: typedefs.JSONObject 604 ) -> activity.CharacterActivity: 605 current_mode: typing.Optional[enums.GameMode] = None 606 if raw_current_mode := payload.get("currentActivityModeType"): 607 current_mode = enums.GameMode(raw_current_mode) 608 609 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 610 if raw_current_modes := payload.get("currentActivityModeTypes"): 611 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 612 613 return activity.CharacterActivity( 614 date_started=time.clean_date(payload["dateActivityStarted"]), 615 current_hash=payload["currentActivityHash"], 616 current_mode_hash=payload["currentActivityModeHash"], 617 current_mode=current_mode, 618 current_mode_hashes=payload.get("currentActivityModeHashes"), 619 current_mode_types=current_mode_types, 620 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 621 last_story_hash=payload["lastCompletedStoryHash"], 622 available_activities=[ 623 self.deserialize_available_activity(activity_) 624 for activity_ in payload["availableActivities"] 625 ], 626 ) 627 628 def deserialize_profile_items( 629 self, payload: typedefs.JSONObject, / 630 ) -> list[profile.ProfileItemImpl]: 631 return [self.deserialize_profile_item(item) for item in payload["items"]] 632 633 def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node: 634 return records.Node( 635 state=int(payload["state"]), 636 objective=self.deserialize_objectives(payload["objective"]) 637 if "objective" in payload 638 else None, 639 progress_value=int(payload["progressValue"]), 640 completion_value=int(payload["completionValue"]), 641 record_category_score=int(payload["recordCategoryScore"]) 642 if "recordCategoryScore" in payload 643 else None, 644 ) 645 646 @staticmethod 647 def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible: 648 recent_collectibles: typing.Optional[collections.Collection[int]] = None 649 if raw_recent_collectibles := payload.get("recentCollectibleHashes"): 650 recent_collectibles = [ 651 int(item_hash) for item_hash in raw_recent_collectibles 652 ] 653 654 collectibles: dict[int, int] = {} 655 for item_hash, mapping in payload["collectibles"].items(): 656 collectibles[int(item_hash)] = int(mapping["state"]) 657 658 return items.Collectible( 659 recent_collectibles=recent_collectibles, 660 collectibles=collectibles, 661 collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]), 662 collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]), 663 ) 664 665 @staticmethod 666 def _deserialize_currencies( 667 payload: typedefs.JSONObject, 668 ) -> collections.Sequence[items.Currency]: 669 return [ 670 items.Currency(hash=int(item_hash), amount=int(amount)) 671 for item_hash, amount in payload["itemQuantities"].items() 672 ] 673 674 def deserialize_progressions( 675 self, payload: typedefs.JSONObject 676 ) -> progressions.Progression: 677 return progressions.Progression( 678 hash=int(payload["progressionHash"]), 679 level=int(payload["level"]), 680 cap=int(payload["levelCap"]), 681 daily_limit=int(payload["dailyLimit"]), 682 weekly_limit=int(payload["weeklyLimit"]), 683 current_progress=int(payload["currentProgress"]), 684 daily_progress=int(payload["dailyProgress"]), 685 needed=int(payload["progressToNextLevel"]), 686 next_level=int(payload["nextLevelAt"]), 687 ) 688 689 def _deserialize_factions( 690 self, payload: typedefs.JSONObject 691 ) -> progressions.Factions: 692 progs = self.deserialize_progressions(payload) 693 return progressions.Factions( 694 hash=progs.hash, 695 level=progs.level, 696 cap=progs.cap, 697 daily_limit=progs.daily_limit, 698 weekly_limit=progs.weekly_limit, 699 current_progress=progs.current_progress, 700 daily_progress=progs.daily_progress, 701 needed=progs.needed, 702 next_level=progs.next_level, 703 faction_hash=payload["factionHash"], 704 faction_vendor_hash=payload["factionVendorIndex"], 705 ) 706 707 def _deserialize_milestone_available_quest( 708 self, payload: typedefs.JSONObject 709 ) -> milestones.MilestoneQuest: 710 return milestones.MilestoneQuest( 711 item_hash=payload["questItemHash"], 712 status=self._deserialize_milestone_quest_status(payload["status"]), 713 ) 714 715 def _deserialize_milestone_activity( 716 self, payload: typedefs.JSONObject 717 ) -> milestones.MilestoneActivity: 718 719 phases: typing.Optional[ 720 collections.Sequence[milestones.MilestoneActivityPhase] 721 ] = None 722 if raw_phases := payload.get("phases"): 723 phases = [ 724 milestones.MilestoneActivityPhase( 725 is_completed=obj["complete"], hash=obj["phaseHash"] 726 ) 727 for obj in raw_phases 728 ] 729 730 return milestones.MilestoneActivity( 731 hash=payload["activityHash"], 732 challenges=[ 733 self.deserialize_objectives(obj["objective"]) 734 for obj in payload["challenges"] 735 ], 736 modifier_hashes=payload.get("modifierHashes"), 737 boolean_options=payload.get("booleanActivityOptions"), 738 phases=phases, 739 ) 740 741 def _deserialize_milestone_quest_status( 742 self, payload: typedefs.JSONObject 743 ) -> milestones.QuestStatus: 744 return milestones.QuestStatus( 745 net=self._net, 746 quest_hash=payload["questHash"], 747 step_hash=payload["stepHash"], 748 step_objectives=[ 749 self.deserialize_objectives(objective) 750 for objective in payload["stepObjectives"] 751 ], 752 is_tracked=payload["tracked"], 753 is_completed=payload["completed"], 754 started=payload["started"], 755 item_instance_id=payload["itemInstanceId"], 756 vendor_hash=payload.get("vendorHash"), 757 is_redeemed=payload["redeemed"], 758 ) 759 760 def _deserialize_milestone_rewards( 761 self, payload: typedefs.JSONObject 762 ) -> milestones.MilestoneReward: 763 return milestones.MilestoneReward( 764 category_hash=payload["rewardCategoryHash"], 765 entries=[ 766 milestones.MilestoneRewardEntry( 767 entry_hash=entry["rewardEntryHash"], 768 is_earned=entry["earned"], 769 is_redeemed=entry["redeemed"], 770 ) 771 for entry in payload["entries"] 772 ], 773 ) 774 775 def deserialize_milestone( 776 self, payload: typedefs.JSONObject 777 ) -> milestones.Milestone: 778 start_date: typing.Optional[datetime.datetime] = None 779 if raw_start_date := payload.get("startDate"): 780 start_date = time.clean_date(raw_start_date) 781 782 end_date: typing.Optional[datetime.datetime] = None 783 if raw_end_date := payload.get("endDate"): 784 end_date = time.clean_date(raw_end_date) 785 786 rewards: typing.Optional[ 787 collections.Collection[milestones.MilestoneReward] 788 ] = None 789 if raw_rewards := payload.get("rewards"): 790 rewards = [ 791 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 792 ] 793 794 activities: typing.Optional[ 795 collections.Sequence[milestones.MilestoneActivity] 796 ] = None 797 if raw_activities := payload.get("activities"): 798 activities = [ 799 self._deserialize_milestone_activity(active) 800 for active in raw_activities 801 ] 802 803 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 804 if raw_quests := payload.get("availableQuests"): 805 quests = [ 806 self._deserialize_milestone_available_quest(quest) 807 for quest in raw_quests 808 ] 809 810 vendors: typing.Optional[ 811 collections.Sequence[milestones.MilestoneVendor] 812 ] = None 813 if raw_vendors := payload.get("vendors"): 814 vendors = [ 815 milestones.MilestoneVendor( 816 vendor_hash=vendor["vendorHash"], 817 preview_itemhash=vendor.get("previewItemHash"), 818 ) 819 for vendor in raw_vendors 820 ] 821 822 return milestones.Milestone( 823 hash=payload["milestoneHash"], 824 start_date=start_date, 825 end_date=end_date, 826 order=payload["order"], 827 rewards=rewards, 828 available_quests=quests, 829 activities=activities, 830 vendors=vendors, 831 ) 832 833 def _deserialize_artifact_tiers( 834 self, payload: typedefs.JSONObject 835 ) -> season.ArtifactTier: 836 return season.ArtifactTier( 837 hash=payload["tierHash"], 838 is_unlocked=payload["isUnlocked"], 839 points_to_unlock=payload["pointsToUnlock"], 840 items=[ 841 season.ArtifactTierItem( 842 hash=item["itemHash"], is_active=item["isActive"] 843 ) 844 for item in payload["items"] 845 ], 846 ) 847 848 def deserialize_characters( 849 self, payload: typedefs.JSONObject 850 ) -> collections.Mapping[int, character.Character]: 851 return { 852 int(char_id): self._set_character_attrs(char) 853 for char_id, char in payload["data"].items() 854 } 855 856 def deserialize_character( 857 self, payload: typedefs.JSONObject 858 ) -> character.Character: 859 return self._set_character_attrs(payload) 860 861 def deserialize_character_equipments( 862 self, payload: typedefs.JSONObject 863 ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]: 864 return { 865 int(char_id): self.deserialize_profile_items(item) 866 for char_id, item in payload["data"].items() 867 } 868 869 def deserialize_character_activities( 870 self, payload: typedefs.JSONObject 871 ) -> collections.Mapping[int, activity.CharacterActivity]: 872 return { 873 int(char_id): self.deserialize_character_activity(data) 874 for char_id, data in payload["data"].items() 875 } 876 877 def deserialize_characters_render_data( 878 self, payload: typedefs.JSONObject 879 ) -> collections.Mapping[int, character.RenderedData]: 880 return { 881 int(char_id): self.deserialize_character_render_data(data) 882 for char_id, data in payload["data"].items() 883 } 884 885 def deserialize_character_progressions( 886 self, payload: typedefs.JSONObject 887 ) -> character.CharacterProgression: 888 progressions_ = { 889 int(prog_id): self.deserialize_progressions(prog) 890 for prog_id, prog in payload["progressions"].items() 891 } 892 893 factions = { 894 int(faction_id): self._deserialize_factions(faction) 895 for faction_id, faction in payload["factions"].items() 896 } 897 898 milestones_ = { 899 int(milestone_hash): self.deserialize_milestone(milestone) 900 for milestone_hash, milestone in payload["milestones"].items() 901 } 902 903 uninstanced_item_objectives = { 904 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 905 for item_hash, obj in payload["uninstancedItemObjectives"].items() 906 } 907 908 artifact = payload["seasonalArtifact"] 909 seasonal_artifact = season.CharacterScopedArtifact( 910 hash=artifact["artifactHash"], 911 points_used=artifact["pointsUsed"], 912 reset_count=artifact["resetCount"], 913 tiers=[ 914 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 915 ], 916 ) 917 checklists = payload["checklists"] 918 919 return character.CharacterProgression( 920 progressions=progressions_, 921 factions=factions, 922 checklists=checklists, 923 milestones=milestones_, 924 seasonal_artifact=seasonal_artifact, 925 uninstanced_item_objectives=uninstanced_item_objectives, 926 ) 927 928 def deserialize_character_progressions_mapping( 929 self, payload: typedefs.JSONObject 930 ) -> collections.Mapping[int, character.CharacterProgression]: 931 character_progressions: collections.Mapping[ 932 int, character.CharacterProgression 933 ] = {} 934 for char_id, data in payload["data"].items(): 935 # A little hack to stop mypy complaining about Mapping <-> dict 936 character_progressions[int(char_id)] = self.deserialize_character_progressions(data) # type: ignore[index] 937 return character_progressions 938 939 def deserialize_characters_records( 940 self, 941 payload: typedefs.JSONObject, 942 ) -> collections.Mapping[int, records.CharacterRecord]: 943 944 return { 945 int(rec_id): self.deserialize_character_records( 946 rec, record_hashes=payload.get("featuredRecordHashes") 947 ) 948 for rec_id, rec in payload["records"].items() 949 } 950 951 def deserialize_profile_records( 952 self, payload: typedefs.JSONObject 953 ) -> collections.Mapping[int, records.Record]: 954 raw_profile_records = payload["data"] 955 scores = records.RecordScores( 956 current_score=raw_profile_records["score"], 957 legacy_score=raw_profile_records["legacyScore"], 958 lifetime_score=raw_profile_records["lifetimeScore"], 959 ) 960 return { 961 int(record_id): self.deserialize_records( 962 record, 963 scores, 964 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 965 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 966 ) 967 for record_id, record in raw_profile_records["records"].items() 968 } 969 970 def _deserialize_craftable_socket_plug( 971 self, payload: typedefs.JSONObject 972 ) -> items.CraftableSocketPlug: 973 return items.CraftableSocketPlug( 974 item_hash=int(payload["plugItemHash"]), 975 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 976 ) 977 978 def _deserialize_craftable_socket( 979 self, payload: typedefs.JSONObject 980 ) -> items.CraftableSocket: 981 982 plugs: list[items.CraftableSocketPlug] = [] 983 if raw_plug := payload.get("plug"): 984 plugs.extend( 985 self._deserialize_craftable_socket_plug(plug) for plug in raw_plug 986 ) 987 988 return items.CraftableSocket( 989 plug_set_hash=int(payload["plugSetHash"]), plugs=plugs 990 ) 991 992 def _deserialize_craftable_item( 993 self, payload: typedefs.JSONObject 994 ) -> items.CraftableItem: 995 996 return items.CraftableItem( 997 is_visible=payload["visible"], 998 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 999 sockets=[ 1000 self._deserialize_craftable_socket(socket) 1001 for socket in payload["sockets"] 1002 ], 1003 ) 1004 1005 def deserialize_craftables_component( 1006 self, payload: typedefs.JSONObject 1007 ) -> components.CraftablesComponent: 1008 return components.CraftablesComponent( 1009 net=self._net, 1010 craftables={ 1011 int(item_id): self._deserialize_craftable_item(item) 1012 for item_id, item in payload["craftables"].items() 1013 if item is not None 1014 }, 1015 crafting_root_node_hash=payload["craftingRootNodeHash"], 1016 ) 1017 1018 def deserialize_components( # noqa: C901 Too complex. 1019 self, payload: typedefs.JSONObject 1020 ) -> components.Component: 1021 1022 profile_: typing.Optional[profile.Profile] = None 1023 if raw_profile := payload.get("profile"): 1024 profile_ = self.deserialize_profile(raw_profile) 1025 1026 profile_progression: typing.Optional[profile.ProfileProgression] = None 1027 if raw_profile_progression := payload.get("profileProgression"): 1028 profile_progression = self.deserialize_profile_progression( 1029 raw_profile_progression 1030 ) 1031 1032 profile_currencies: typing.Optional[ 1033 collections.Sequence[profile.ProfileItemImpl] 1034 ] = None 1035 if raw_profile_currencies := payload.get("profileCurrencies"): 1036 if "data" in raw_profile_currencies: 1037 profile_currencies = self.deserialize_profile_items( 1038 raw_profile_currencies["data"] 1039 ) 1040 1041 profile_inventories: typing.Optional[ 1042 collections.Sequence[profile.ProfileItemImpl] 1043 ] = None 1044 if raw_profile_inventories := payload.get("profileInventory"): 1045 if "data" in raw_profile_inventories: 1046 profile_inventories = self.deserialize_profile_items( 1047 raw_profile_inventories["data"] 1048 ) 1049 1050 profile_records: typing.Optional[ 1051 collections.Mapping[int, records.Record] 1052 ] = None 1053 1054 if raw_profile_records_ := payload.get("profileRecords"): 1055 profile_records = self.deserialize_profile_records(raw_profile_records_) 1056 1057 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1058 if raw_characters := payload.get("characters"): 1059 characters = self.deserialize_characters(raw_characters) 1060 1061 character_records: typing.Optional[ 1062 collections.Mapping[int, records.CharacterRecord] 1063 ] = None 1064 1065 if raw_character_records := payload.get("characterRecords"): 1066 # Had to do it in two steps.. 1067 to_update: typedefs.JSONObject = {} 1068 for _, data in raw_character_records["data"].items(): 1069 for record_id, record in data.items(): 1070 to_update[record_id] = record 1071 1072 character_records = { 1073 int(rec_id): self.deserialize_character_records( 1074 rec, record_hashes=to_update.get("featuredRecordHashes") 1075 ) 1076 for rec_id, rec in to_update["records"].items() 1077 } 1078 1079 character_equipments: typing.Optional[ 1080 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1081 ] = None 1082 if raw_character_equips := payload.get("characterEquipment"): 1083 character_equipments = self.deserialize_character_equipments( 1084 raw_character_equips 1085 ) 1086 1087 character_inventories: typing.Optional[ 1088 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1089 ] = None 1090 if raw_character_inventories := payload.get("characterInventories"): 1091 if "data" in raw_character_inventories: 1092 character_inventories = self.deserialize_character_equipments( 1093 raw_character_inventories 1094 ) 1095 1096 character_activities: typing.Optional[ 1097 collections.Mapping[int, activity.CharacterActivity] 1098 ] = None 1099 if raw_char_acts := payload.get("characterActivities"): 1100 character_activities = self.deserialize_character_activities(raw_char_acts) 1101 1102 character_render_data: typing.Optional[ 1103 collections.Mapping[int, character.RenderedData] 1104 ] = None 1105 if raw_character_render_data := payload.get("characterRenderData"): 1106 character_render_data = self.deserialize_characters_render_data( 1107 raw_character_render_data 1108 ) 1109 1110 character_progressions: typing.Optional[ 1111 collections.Mapping[int, character.CharacterProgression] 1112 ] = None 1113 1114 if raw_character_progressions := payload.get("characterProgressions"): 1115 character_progressions = self.deserialize_character_progressions_mapping( 1116 raw_character_progressions 1117 ) 1118 1119 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1120 if raw_profile_string_vars := payload.get("profileStringVariables"): 1121 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1122 1123 character_string_vars: typing.Optional[ 1124 collections.Mapping[int, collections.Mapping[int, int]] 1125 ] = None 1126 if raw_character_string_vars := payload.get("characterStringVariables"): 1127 character_string_vars = { 1128 int(char_id): data["integerValuesByHash"] 1129 for char_id, data in raw_character_string_vars["data"].items() 1130 } 1131 1132 metrics: typing.Optional[ 1133 collections.Sequence[ 1134 collections.Mapping[ 1135 int, tuple[bool, typing.Optional[records.Objective]] 1136 ] 1137 ] 1138 ] = None 1139 root_node_hash: typing.Optional[int] = None 1140 1141 if raw_metrics := payload.get("metrics"): 1142 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1143 metrics = [ 1144 { 1145 int(metrics_hash): ( 1146 data["invisible"], 1147 self.deserialize_objectives(data["objectiveProgress"]) 1148 if "objectiveProgress" in data 1149 else None, 1150 ) 1151 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1152 } 1153 ] 1154 transitory: typing.Optional[fireteams.FireteamParty] = None 1155 if raw_transitory := payload.get("profileTransitoryData"): 1156 if "data" in raw_transitory: 1157 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1158 1159 item_components: typing.Optional[components.ItemsComponent] = None 1160 if raw_item_components := payload.get("itemComponents"): 1161 item_components = self.deserialize_items_component(raw_item_components) 1162 1163 profile_plugsets: typing.Optional[ 1164 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1165 ] = None 1166 1167 if raw_profile_plugs := payload.get("profilePlugSets"): 1168 profile_plugsets = { 1169 int(index): [self.deserialize_plug_item_state(state) for state in data] 1170 for index, data in raw_profile_plugs["data"]["plugs"].items() 1171 } 1172 1173 character_plugsets: typing.Optional[ 1174 collections.Mapping[ 1175 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1176 ] 1177 ] = None 1178 if raw_char_plugsets := payload.get("characterPlugSets"): 1179 character_plugsets = { 1180 int(char_id): { 1181 int(index): [ 1182 self.deserialize_plug_item_state(state) for state in data 1183 ] 1184 for index, data in inner["plugs"].items() 1185 } 1186 for char_id, inner in raw_char_plugsets["data"].items() 1187 } 1188 1189 character_collectibles: typing.Optional[ 1190 collections.Mapping[int, items.Collectible] 1191 ] = None 1192 if raw_character_collectibles := payload.get("characterCollectibles"): 1193 character_collectibles = { 1194 int(char_id): self._deserialize_collectible(data) 1195 for char_id, data in raw_character_collectibles["data"].items() 1196 } 1197 1198 profile_collectibles: typing.Optional[items.Collectible] = None 1199 if raw_profile_collectibles := payload.get("profileCollectibles"): 1200 profile_collectibles = self._deserialize_collectible( 1201 raw_profile_collectibles["data"] 1202 ) 1203 1204 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1205 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1206 profile_nodes = { 1207 int(node_hash): self._deserialize_node(node) 1208 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1209 } 1210 1211 character_nodes: typing.Optional[ 1212 collections.Mapping[int, collections.Mapping[int, records.Node]] 1213 ] = None 1214 if raw_character_nodes := payload.get("characterPresentationNodes"): 1215 character_nodes = { 1216 int(char_id): { 1217 int(node_hash): self._deserialize_node(node) 1218 for node_hash, node in each_character["nodes"].items() 1219 } 1220 for char_id, each_character in raw_character_nodes["data"].items() 1221 } 1222 1223 platform_silver: typing.Optional[ 1224 collections.Mapping[str, profile.ProfileItemImpl] 1225 ] = None 1226 if raw_platform_silver := payload.get("platformSilver"): 1227 if "data" in raw_platform_silver: 1228 platform_silver = { 1229 platform_name: self.deserialize_profile_item(item) 1230 for platform_name, item in raw_platform_silver["data"][ 1231 "platformSilver" 1232 ].items() 1233 } 1234 1235 character_currency_lookups: typing.Optional[ 1236 collections.Mapping[int, collections.Sequence[items.Currency]] 1237 ] = None 1238 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1239 if "data" in raw_char_lookups: 1240 character_currency_lookups = { 1241 int(char_id): self._deserialize_currencies(currencie) 1242 for char_id, currencie in raw_char_lookups["data"].items() 1243 } 1244 1245 character_craftables: typing.Optional[ 1246 collections.Mapping[int, components.CraftablesComponent] 1247 ] = None 1248 if raw_character_craftables := payload.get("characterCraftables"): 1249 1250 if "data" in raw_character_craftables: 1251 character_craftables = { 1252 int(char_id): self.deserialize_craftables_component(craftable) 1253 for char_id, craftable in raw_character_craftables["data"].items() 1254 } 1255 1256 return components.Component( 1257 profiles=profile_, 1258 profile_progression=profile_progression, 1259 profile_currencies=profile_currencies, 1260 profile_inventories=profile_inventories, 1261 profile_records=profile_records, 1262 characters=characters, 1263 character_records=character_records, 1264 character_equipments=character_equipments, 1265 character_inventories=character_inventories, 1266 character_activities=character_activities, 1267 character_render_data=character_render_data, 1268 character_progressions=character_progressions, 1269 profile_string_variables=profile_string_vars, 1270 character_string_variables=character_string_vars, 1271 metrics=metrics, 1272 root_node_hash=root_node_hash, 1273 transitory=transitory, 1274 item_components=item_components, 1275 profile_plugsets=profile_plugsets, 1276 character_plugsets=character_plugsets, 1277 character_collectibles=character_collectibles, 1278 profile_collectibles=profile_collectibles, 1279 profile_nodes=profile_nodes, 1280 character_nodes=character_nodes, 1281 platform_silver=platform_silver, 1282 character_currency_lookups=character_currency_lookups, 1283 character_craftables=character_craftables, 1284 ) 1285 1286 def deserialize_items_component( 1287 self, payload: typedefs.JSONObject 1288 ) -> components.ItemsComponent: 1289 instances: typing.Optional[ 1290 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1291 ] = None 1292 if raw_instances := payload.get("instances"): 1293 instances = [ 1294 { 1295 int(ins_id): self.deserialize_instanced_item(item) 1296 for ins_id, item in raw_instances["data"].items() 1297 } 1298 ] 1299 1300 render_data: typing.Optional[ 1301 collections.Mapping[int, tuple[bool, dict[int, int]]] 1302 ] = None 1303 if raw_render_data := payload.get("renderData"): 1304 render_data = { 1305 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1306 for ins_id, data in raw_render_data["data"].items() 1307 } 1308 1309 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1310 if raw_stats := payload.get("stats"): 1311 builder: collections.Mapping[int, items.ItemStatsView] = {} 1312 for ins_id, stat in raw_stats["data"].items(): 1313 for _, items_ in stat.items(): 1314 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1315 stats = builder 1316 1317 sockets: typing.Optional[ 1318 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1319 ] = None 1320 if raw_sockets := payload.get("sockets"): 1321 sockets = { 1322 int(ins_id): [ 1323 self.deserialize_item_socket(socket) for socket in item["sockets"] 1324 ] 1325 for ins_id, item in raw_sockets["data"].items() 1326 } 1327 1328 objeectives: typing.Optional[ 1329 collections.Mapping[int, collections.Sequence[records.Objective]] 1330 ] = None 1331 if raw_objectives := payload.get("objectives"): 1332 objeectives = { 1333 int(ins_id): [self.deserialize_objectives(objective)] 1334 for ins_id, data in raw_objectives["data"].items() 1335 for objective in data["objectives"] 1336 } 1337 1338 perks: typing.Optional[ 1339 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1340 ] = None 1341 if raw_perks := payload.get("perks"): 1342 perks = { 1343 int(ins_id): [ 1344 self.deserialize_item_perk(perk) for perk in item["perks"] 1345 ] 1346 for ins_id, item in raw_perks["data"].items() 1347 } 1348 1349 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1350 if raw_plug_states := payload.get("plugStates"): 1351 pending_states: list[items.PlugItemState] = [] 1352 for _, plug in raw_plug_states["data"].items(): 1353 pending_states.append(self.deserialize_plug_item_state(plug)) 1354 plug_states = pending_states 1355 1356 reusable_plugs: typing.Optional[ 1357 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1358 ] = None 1359 if raw_re_plugs := payload.get("reusablePlugs"): 1360 reusable_plugs = { 1361 int(ins_id): [ 1362 self.deserialize_plug_item_state(state) for state in inner 1363 ] 1364 for ins_id, plug in raw_re_plugs["data"].items() 1365 for inner in list(plug["plugs"].values()) 1366 } 1367 1368 plug_objectives: typing.Optional[ 1369 collections.Mapping[ 1370 int, collections.Mapping[int, collections.Collection[records.Objective]] 1371 ] 1372 ] = None 1373 if raw_plug_objectives := payload.get("plugObjectives"): 1374 plug_objectives = { 1375 int(ins_id): { 1376 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1377 for obj_hash, objs in inner["objectivesPerPlug"].items() 1378 } 1379 for ins_id, inner in raw_plug_objectives["data"].items() 1380 } 1381 1382 return components.ItemsComponent( 1383 sockets=sockets, 1384 stats=stats, 1385 render_data=render_data, 1386 instances=instances, 1387 objectives=objeectives, 1388 perks=perks, 1389 plug_states=plug_states, 1390 reusable_plugs=reusable_plugs, 1391 plug_objectives=plug_objectives, 1392 ) 1393 1394 def deserialize_character_component( # type: ignore[call-arg] 1395 self, payload: typedefs.JSONObject 1396 ) -> components.CharacterComponent: 1397 1398 character_: typing.Optional[character.Character] = None 1399 if raw_singuler_character := payload.get("character"): 1400 character_ = self.deserialize_character(raw_singuler_character["data"]) 1401 1402 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1403 if raw_inventory := payload.get("inventory"): 1404 if "data" in raw_inventory: 1405 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1406 1407 activities: typing.Optional[activity.CharacterActivity] = None 1408 if raw_activities := payload.get("activities"): 1409 activities = self.deserialize_character_activity(raw_activities["data"]) 1410 1411 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1412 if raw_equipments := payload.get("equipment"): 1413 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1414 1415 progressions_: typing.Optional[character.CharacterProgression] = None 1416 if raw_progressions := payload.get("progressions"): 1417 progressions_ = self.deserialize_character_progressions( 1418 raw_progressions["data"] 1419 ) 1420 1421 render_data: typing.Optional[character.RenderedData] = None 1422 if raw_render_data := payload.get("renderData"): 1423 render_data = self.deserialize_character_render_data( 1424 raw_render_data["data"] 1425 ) 1426 1427 character_records: typing.Optional[ 1428 collections.Mapping[int, records.CharacterRecord] 1429 ] = None 1430 if raw_char_records := payload.get("records"): 1431 character_records = self.deserialize_characters_records( 1432 raw_char_records["data"] 1433 ) 1434 1435 item_components: typing.Optional[components.ItemsComponent] = None 1436 if raw_item_components := payload.get("itemComponents"): 1437 item_components = self.deserialize_items_component(raw_item_components) 1438 1439 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1440 if raw_nodes := payload.get("presentationNodes"): 1441 nodes = { 1442 int(node_hash): self._deserialize_node(node) 1443 for node_hash, node in raw_nodes["data"]["nodes"].items() 1444 } 1445 1446 collectibles: typing.Optional[items.Collectible] = None 1447 if raw_collectibles := payload.get("collectibles"): 1448 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1449 1450 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1451 if raw_currencies := payload.get("currencyLookups"): 1452 if "data" in raw_currencies: 1453 currency_lookups = self._deserialize_currencies(raw_currencies) 1454 1455 return components.CharacterComponent( 1456 activities=activities, 1457 equipment=equipment, 1458 inventory=inventory, 1459 progressions=progressions_, 1460 render_data=render_data, 1461 character=character_, 1462 character_records=character_records, 1463 profile_records=None, 1464 item_components=item_components, 1465 currency_lookups=currency_lookups, 1466 collectibles=collectibles, 1467 nodes=nodes, 1468 ) 1469 1470 def _set_entity_attrs( 1471 self, payload: typedefs.JSONObject, *, key: str = "displayProperties" 1472 ) -> entity.Entity: 1473 1474 name: undefined.UndefinedOr[str] = undefined.Undefined 1475 description: undefined.UndefinedOr[str] = undefined.Undefined 1476 1477 if properties := payload[key]: 1478 if (raw_name := properties["name"]) is not typedefs.Unknown: 1479 name = raw_name 1480 1481 if ( 1482 raw_description := properties["description"] 1483 ) and not typedefs.is_unknown(raw_description): 1484 description = raw_description 1485 1486 return entity.Entity( 1487 net=self._net, 1488 hash=payload["hash"], 1489 index=payload["index"], 1490 name=name, 1491 description=description, 1492 has_icon=properties["hasIcon"], 1493 icon=assets.Image(properties["icon"] if "icon" in properties else None), 1494 ) 1495 1496 def deserialize_inventory_results( 1497 self, payload: typedefs.JSONObject 1498 ) -> iterators.FlatIterator[entity.SearchableEntity]: 1499 suggested_words: list[str] = payload["suggestedWords"] 1500 1501 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1502 return s if not typedefs.is_unknown(s) else undefined.Undefined 1503 1504 return iterators.FlatIterator( 1505 [ 1506 entity.SearchableEntity( 1507 net=self._net, 1508 hash=data["hash"], 1509 entity_type=data["entityType"], 1510 weight=data["weight"], 1511 suggested_words=suggested_words, 1512 name=data["displayProperties"]["name"], 1513 has_icon=data["displayProperties"]["hasIcon"], 1514 description=_check_unknown( 1515 data["displayProperties"]["description"] 1516 ), 1517 icon=assets.Image(data["displayProperties"]["icon"]), 1518 ) 1519 for data in payload["results"]["results"] 1520 ] 1521 ) 1522 1523 def _deserialize_inventory_item_objects( 1524 self, payload: typedefs.JSONObject 1525 ) -> entity.InventoryEntityObjects: 1526 return entity.InventoryEntityObjects( 1527 action=payload.get("action"), 1528 set_data=payload.get("setData"), 1529 stats=payload.get("stats"), 1530 equipping_block=payload.get("equippingBlock"), 1531 translation_block=payload.get("translationBlock"), 1532 preview=payload.get("preview"), 1533 quality=payload.get("quality"), 1534 value=payload.get("value"), 1535 source_data=payload.get("sourceData"), 1536 objectives=payload.get("objectives"), 1537 plug=payload.get("plug"), 1538 metrics=payload.get("metrics"), 1539 gearset=payload.get("gearset"), 1540 sack=payload.get("sack"), 1541 sockets=payload.get("sockets"), 1542 summary=payload.get("summary"), 1543 talent_gird=payload.get("talentGrid"), 1544 investments_stats=payload.get("investmentStats"), 1545 perks=payload.get("perks"), 1546 animations=payload.get("animations", []), 1547 links=payload.get("links", []), 1548 ) 1549 1550 def deserialize_inventory_entity( # noqa: C901 Too complex. 1551 self, payload: typedefs.JSONObject, / 1552 ) -> entity.InventoryEntity: 1553 1554 props = self._set_entity_attrs(payload) 1555 objects = self._deserialize_inventory_item_objects(payload) 1556 1557 collectible_hash: typing.Optional[int] = None 1558 if raw_collectible_hash := payload.get("collectibleHash"): 1559 collectible_hash = int(raw_collectible_hash) 1560 1561 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1562 if raw_second_icon := payload.get("secondaryIcon"): 1563 secondary_icon = assets.Image(raw_second_icon) 1564 1565 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1566 if raw_second_overlay := payload.get("secondaryOverlay"): 1567 secondary_overlay = assets.Image(raw_second_overlay) 1568 1569 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1570 if raw_second_special := payload.get("secondarySpecial"): 1571 secondary_special = assets.Image(raw_second_special) 1572 1573 screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1574 if raw_screenshot := payload.get("screenshot"): 1575 screenshot = assets.Image(raw_screenshot) 1576 1577 watermark_icon: typing.Optional[assets.Image] = None 1578 if raw_watermark_icon := payload.get("iconWatermark"): 1579 watermark_icon = assets.Image(raw_watermark_icon) 1580 1581 watermark_shelved: typing.Optional[assets.Image] = None 1582 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1583 watermark_shelved = assets.Image(raw_watermark_shelved) 1584 1585 about: undefined.UndefinedOr[str] = undefined.Undefined 1586 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1587 raw_about 1588 ): 1589 about = raw_about 1590 1591 ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined 1592 if ( 1593 raw_ui_style := payload.get("uiItemDisplayStyle") 1594 ) and not typedefs.is_unknown(raw_ui_style): 1595 ui_item_style = raw_ui_style 1596 1597 tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined 1598 if ( 1599 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1600 ) and not typedefs.is_unknown(raw_tier_and_name): 1601 tier_and_name = raw_tier_and_name 1602 1603 type_name: undefined.UndefinedOr[str] = undefined.Undefined 1604 if ( 1605 raw_type_name := payload.get("itemTypeDisplayName") 1606 ) and not typedefs.is_unknown(raw_type_name): 1607 type_name = raw_type_name 1608 1609 display_source: undefined.UndefinedOr[str] = undefined.Undefined 1610 if ( 1611 raw_display_source := payload.get("displaySource") 1612 ) and not typedefs.is_unknown(raw_display_source): 1613 display_source = raw_display_source 1614 1615 lorehash: typing.Optional[int] = None 1616 if raw_lore_hash := payload.get("loreHash"): 1617 lorehash = int(raw_lore_hash) 1618 1619 summary_hash: typing.Optional[int] = None 1620 if raw_summary_hash := payload.get("summaryItemHash"): 1621 summary_hash = raw_summary_hash 1622 1623 breaker_type_hash: typing.Optional[int] = None 1624 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1625 breaker_type_hash = int(raw_breaker_type_hash) 1626 1627 damage_types: typing.Optional[collections.Sequence[int]] = None 1628 if raw_damage_types := payload.get("damageTypes"): 1629 damage_types = [int(type_) for type_ in raw_damage_types] 1630 1631 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1632 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1633 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1634 1635 default_damagetype_hash: typing.Optional[int] = None 1636 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1637 default_damagetype_hash = int(raw_defaultdmg_hash) 1638 1639 emblem_objective_hash: typing.Optional[int] = None 1640 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1641 emblem_objective_hash = int(raw_emblem_obj_hash) 1642 1643 tier_type: typing.Optional[enums.TierType] = None 1644 tier: typing.Optional[enums.ItemTier] = None 1645 bucket_hash: typing.Optional[int] = None 1646 recovery_hash: typing.Optional[int] = None 1647 tier_name: undefined.UndefinedOr[str] = undefined.Undefined 1648 isinstance_item: bool = False 1649 expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined 1650 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined 1651 suppress_expiration: bool = False 1652 max_stack_size: typing.Optional[int] = None 1653 stack_label: undefined.UndefinedOr[str] = undefined.Undefined 1654 1655 if inventory := payload.get("inventory"): 1656 tier_type = enums.TierType(int(inventory["tierType"])) 1657 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1658 bucket_hash = int(inventory["bucketTypeHash"]) 1659 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1660 tier_name = inventory["tierTypeName"] 1661 isinstance_item = inventory["isInstanceItem"] 1662 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1663 max_stack_size = int(inventory["maxStackSize"]) 1664 1665 try: 1666 stack_label = inventory["stackUniqueLabel"] 1667 except KeyError: 1668 pass 1669 1670 return entity.InventoryEntity( 1671 net=self._net, 1672 collectible_hash=collectible_hash, 1673 name=props.name, 1674 about=about, 1675 emblem_objective_hash=emblem_objective_hash, 1676 suppress_expiration=suppress_expiration, 1677 max_stack_size=max_stack_size, 1678 stack_label=stack_label, 1679 tier=tier, 1680 tier_type=tier_type, 1681 tier_name=tier_name, 1682 bucket_hash=bucket_hash, 1683 recovery_bucket_hash=recovery_hash, 1684 isinstance_item=isinstance_item, 1685 expire_in_orbit_message=expire_in_orbit_message, 1686 expiration_tooltip=expire_tool_tip, 1687 lore_hash=lorehash, 1688 type_and_tier_name=tier_and_name, 1689 summary_hash=summary_hash, 1690 ui_display_style=ui_item_style, 1691 type_name=type_name, 1692 breaker_type_hash=breaker_type_hash, 1693 description=props.description, 1694 display_source=display_source, 1695 hash=props.hash, 1696 damage_types=damage_types, 1697 index=props.index, 1698 icon=props.icon, 1699 has_icon=props.has_icon, 1700 screenshot=screenshot, 1701 watermark_icon=watermark_icon, 1702 watermark_shelved=watermark_shelved, 1703 secondary_icon=secondary_icon, 1704 secondary_overlay=secondary_overlay, 1705 secondary_special=secondary_special, 1706 type=enums.ItemType(int(payload["itemType"])), 1707 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1708 trait_ids=[trait for trait in payload.get("traitIds", [])], 1709 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1710 item_class=enums.Class(int(payload["classType"])), 1711 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1712 breaker_type=int(payload["breakerType"]), 1713 default_damagetype=int(payload["defaultDamageType"]), 1714 default_damagetype_hash=default_damagetype_hash, 1715 damagetype_hashes=damagetype_hashes, 1716 tooltip_notifications=payload["tooltipNotifications"], 1717 not_transferable=payload["nonTransferrable"], 1718 allow_actions=payload["allowActions"], 1719 is_equippable=payload["equippable"], 1720 objects=objects, 1721 background_colors=payload.get("backgroundColor", {}), 1722 season_hash=payload.get("seasonHash"), 1723 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1724 ) 1725 1726 def deserialize_objective_entity( 1727 self, payload: typedefs.JSONObject, / 1728 ) -> entity.ObjectiveEntity: 1729 props = self._set_entity_attrs(payload) 1730 return entity.ObjectiveEntity( 1731 net=self._net, 1732 hash=props.hash, 1733 index=props.index, 1734 description=props.description, 1735 name=props.name, 1736 has_icon=props.has_icon, 1737 icon=props.icon, 1738 unlock_value_hash=payload["unlockValueHash"], 1739 completion_value=payload["completionValue"], 1740 scope=entity.GatingScope(int(payload["scope"])), 1741 location_hash=payload["locationHash"], 1742 allowed_negative_value=payload["allowNegativeValue"], 1743 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1744 counting_downward=payload["isCountingDownward"], 1745 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1746 progress_description=payload["progressDescription"], 1747 perks=payload["perks"], 1748 stats=payload["stats"], 1749 minimum_visibility=payload["minimumVisibilityThreshold"], 1750 allow_over_completion=payload["allowOvercompletion"], 1751 show_value_style=payload["showValueOnComplete"], 1752 display_only_objective=payload["isDisplayOnlyObjective"], 1753 complete_value_style=entity.ValueUIStyle( 1754 int(payload["completedValueStyle"]) 1755 ), 1756 progress_value_style=entity.ValueUIStyle( 1757 int(payload["inProgressValueStyle"]) 1758 ), 1759 ui_label=payload["uiLabel"], 1760 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1761 ) 1762 1763 def _deserialize_activity_values( 1764 self, payload: typedefs.JSONObject, / 1765 ) -> activity.ActivityValues: 1766 team: typing.Optional[int] = None 1767 if raw_team := payload.get("team"): 1768 team = raw_team["basic"]["value"] 1769 return activity.ActivityValues( 1770 assists=payload["assists"]["basic"]["value"], 1771 deaths=payload["deaths"]["basic"]["value"], 1772 kills=payload["kills"]["basic"]["value"], 1773 is_completed=bool(payload["completed"]["basic"]["value"]), 1774 opponents_defeated=payload["opponentsDefeated"]["basic"]["value"], 1775 efficiency=payload["efficiency"]["basic"]["value"], 1776 kd_ratio=payload["killsDeathsRatio"]["basic"]["value"], 1777 kd_assists=payload["killsDeathsAssists"]["basic"]["value"], 1778 score=payload["score"]["basic"]["value"], 1779 duration=payload["activityDurationSeconds"]["basic"]["displayValue"], 1780 team=team, 1781 completion_reason=payload["completionReason"]["basic"]["displayValue"], 1782 fireteam_id=payload["fireteamId"]["basic"]["value"], 1783 start_seconds=payload["startSeconds"]["basic"]["value"], 1784 played_time=payload["timePlayedSeconds"]["basic"]["displayValue"], 1785 player_count=payload["playerCount"]["basic"]["value"], 1786 team_score=payload["teamScore"]["basic"]["value"], 1787 ) 1788 1789 def deserialize_activity( 1790 self, 1791 payload: typedefs.JSONObject, 1792 /, 1793 ) -> activity.Activity: 1794 period = time.clean_date(payload["period"]) 1795 details = payload["activityDetails"] 1796 ref_id = int(details["referenceId"]) 1797 instance_id = int(details["instanceId"]) 1798 mode = enums.GameMode(details["mode"]) 1799 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1800 is_private = details["isPrivate"] 1801 membership_type = enums.MembershipType(int(details["membershipType"])) 1802 1803 # Since we're using the same fields for post activity method 1804 # this check is required since post activity doesn't values values 1805 values = self._deserialize_activity_values(payload["values"]) 1806 1807 return activity.Activity( 1808 net=self._net, 1809 hash=ref_id, 1810 instance_id=instance_id, 1811 mode=mode, 1812 modes=modes, 1813 is_private=is_private, 1814 membership_type=membership_type, 1815 occurred_at=period, 1816 values=values, 1817 ) 1818 1819 def deserialize_activities( 1820 self, payload: typedefs.JSONObject 1821 ) -> iterators.FlatIterator[activity.Activity]: 1822 return iterators.FlatIterator( 1823 [ 1824 self.deserialize_activity(activity_) 1825 for activity_ in payload["activities"] 1826 ] 1827 ) 1828 1829 def deserialize_extended_weapon_values( 1830 self, payload: typedefs.JSONObject 1831 ) -> activity.ExtendedWeaponValues: 1832 1833 assists: typing.Optional[int] = None 1834 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1835 assists = raw_assists["basic"]["value"] 1836 assists_damage: typing.Optional[int] = None 1837 1838 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1839 assists_damage = raw_assists_damage["basic"]["value"] 1840 1841 return activity.ExtendedWeaponValues( 1842 reference_id=int(payload["referenceId"]), 1843 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1844 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1845 "value" 1846 ], 1847 assists=assists, 1848 assists_damage=assists_damage, 1849 precision_kills_percentage=( 1850 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1851 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1852 "displayValue" 1853 ], 1854 ), 1855 ) 1856 1857 def _deserialize_extended_values( 1858 self, payload: typedefs.JSONObject 1859 ) -> activity.ExtendedValues: 1860 weapons: typing.Optional[ 1861 collections.Collection[activity.ExtendedWeaponValues] 1862 ] = None 1863 1864 if raw_weapons := payload.get("weapons"): 1865 weapons = [ 1866 self.deserialize_extended_weapon_values(value) for value in raw_weapons 1867 ] 1868 1869 return activity.ExtendedValues( 1870 precision_kills=payload["values"]["precisionKills"]["basic"]["value"], 1871 grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"], 1872 melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"], 1873 super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"], 1874 ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"], 1875 weapons=weapons, 1876 ) 1877 1878 def deserialize_post_activity_player( 1879 self, payload: typedefs.JSONObject, / 1880 ) -> activity.PostActivityPlayer: 1881 player = payload["player"] 1882 1883 class_hash: typedefs.NoneOr[int] = None 1884 if (class_hash := player.get("classHash")) is not None: 1885 class_hash = class_hash 1886 1887 race_hash: typedefs.NoneOr[int] = None 1888 if (race_hash := player.get("raceHash")) is not None: 1889 race_hash = race_hash 1890 1891 gender_hash: typedefs.NoneOr[int] = None 1892 if (gender_hash := player.get("genderHash")) is not None: 1893 gender_hash = gender_hash 1894 1895 character_class: undefined.UndefinedOr[str] = undefined.Undefined 1896 if ( 1897 character_class := player.get("characterClass") 1898 ) and not typedefs.is_unknown(character_class): 1899 character_class = character_class 1900 1901 character_level: typedefs.NoneOr[int] = None 1902 if (character_level := player.get("characterLevel")) is not None: 1903 character_level = character_level 1904 1905 return activity.PostActivityPlayer( 1906 standing=int(payload["standing"]), 1907 score=int(payload["score"]["basic"]["value"]), 1908 character_id=payload["characterId"], 1909 destiny_user=self.deserialize_destiny_membership( 1910 player["destinyUserInfo"] 1911 ), 1912 character_class=character_class, 1913 character_level=character_level, 1914 race_hash=race_hash, 1915 gender_hash=gender_hash, 1916 class_hash=class_hash, 1917 light_level=int(player["lightLevel"]), 1918 emblem_hash=int(player["emblemHash"]), 1919 values=self._deserialize_activity_values(payload["values"]), 1920 extended_values=self._deserialize_extended_values(payload["extended"]), 1921 ) 1922 1923 def _deserialize_post_activity_team( 1924 self, payload: typedefs.JSONObject 1925 ) -> activity.PostActivityTeam: 1926 return activity.PostActivityTeam( 1927 id=payload["teamId"], 1928 is_defeated=bool(payload["standing"]["basic"]["value"]), 1929 score=int(payload["score"]["basic"]["value"]), 1930 name=payload["teamName"], 1931 ) 1932 1933 def deserialize_post_activity( 1934 self, payload: typedefs.JSONObject 1935 ) -> activity.PostActivity: 1936 period = time.clean_date(payload["period"]) 1937 details = payload["activityDetails"] 1938 ref_id = int(details["referenceId"]) 1939 instance_id = int(details["instanceId"]) 1940 mode = enums.GameMode(details["mode"]) 1941 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1942 is_private = details["isPrivate"] 1943 membership_type = enums.MembershipType(int(details["membershipType"])) 1944 return activity.PostActivity( 1945 net=self._net, 1946 hash=ref_id, 1947 membership_type=membership_type, 1948 instance_id=instance_id, 1949 mode=mode, 1950 modes=modes, 1951 is_private=is_private, 1952 occurred_at=period, 1953 starting_phase=int(payload["startingPhaseIndex"]), 1954 players=[ 1955 self.deserialize_post_activity_player(player) 1956 for player in payload["entries"] 1957 ], 1958 teams=[ 1959 self._deserialize_post_activity_team(team) for team in payload["teams"] 1960 ], 1961 ) 1962 1963 def _deserialize_aggregated_activity_values( 1964 self, payload: typedefs.JSONObject 1965 ) -> activity.AggregatedActivityValues: 1966 # This ID is always the same for all aggregated values. 1967 activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"]) 1968 1969 return activity.AggregatedActivityValues( 1970 id=activity_id, 1971 fastest_completion_time=( 1972 int(payload["fastestCompletionMsForActivity"]["basic"]["value"]), 1973 payload["fastestCompletionMsForActivity"]["basic"]["displayValue"], 1974 ), 1975 completions=int(payload["activityCompletions"]["basic"]["value"]), 1976 kills=int(payload["activityKills"]["basic"]["value"]), 1977 deaths=int(payload["activityDeaths"]["basic"]["value"]), 1978 assists=int(payload["activityAssists"]["basic"]["value"]), 1979 seconds_played=( 1980 int(payload["activitySecondsPlayed"]["basic"]["value"]), 1981 payload["activitySecondsPlayed"]["basic"]["displayValue"], 1982 ), 1983 wins=int(payload["activityWins"]["basic"]["value"]), 1984 goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]), 1985 special_actions=int(payload["activitySpecialActions"]["basic"]["value"]), 1986 best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]), 1987 best_single_score=int( 1988 payload["activityBestSingleGameScore"]["basic"]["value"] 1989 ), 1990 goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]), 1991 special_score=int(payload["activitySpecialScore"]["basic"]["value"]), 1992 kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]), 1993 kd_ratio=float( 1994 payload["activityKillsDeathsAssists"]["basic"]["displayValue"] 1995 ), 1996 precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]), 1997 ) 1998 1999 def deserialize_aggregated_activity( 2000 self, payload: typedefs.JSONObject 2001 ) -> activity.AggregatedActivity: 2002 return activity.AggregatedActivity( 2003 hash=int(payload["activityHash"]), 2004 values=self._deserialize_aggregated_activity_values(payload["values"]), 2005 ) 2006 2007 def deserialize_aggregated_activities( 2008 self, payload: typedefs.JSONObject 2009 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 2010 return iterators.FlatIterator( 2011 [ 2012 self.deserialize_aggregated_activity(activity) 2013 for activity in payload["activities"] 2014 ] 2015 ) 2016 2017 def deserialize_linked_profiles( 2018 self, payload: typedefs.JSONObject 2019 ) -> profile.LinkedProfile: 2020 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 2021 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2022 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2023 2024 if raw_profile := payload.get("profiles"): 2025 for pfile in raw_profile: 2026 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2027 2028 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2029 for raw_error_pfile in raw_profiles_with_errors: 2030 if error_pfile := raw_error_pfile.get("infoCard"): 2031 error_profiles_vec.append( 2032 self.deserialize_destiny_membership(error_pfile) 2033 ) 2034 2035 return profile.LinkedProfile( 2036 net=self._net, 2037 bungie=bungie_user, 2038 profiles=profiles_vec, 2039 profiles_with_errors=error_profiles_vec, 2040 ) 2041 2042 def deserialize_clan_banners( 2043 self, payload: typedefs.JSONObject 2044 ) -> collections.Sequence[clans.ClanBanner]: 2045 banners_seq: typing.MutableSequence[clans.ClanBanner] = [] 2046 if banners := payload.get("clanBannerDecals"): 2047 for k, v in banners.items(): 2048 banner_obj = clans.ClanBanner( 2049 id=int(k), 2050 foreground=assets.Image(v["foregroundPath"]), 2051 background=assets.Image(v["backgroundPath"]), 2052 ) 2053 banners_seq.append(banner_obj) 2054 return banners_seq 2055 2056 def deserialize_public_milestone_content( 2057 self, payload: typedefs.JSONObject 2058 ) -> milestones.MilestoneContent: 2059 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2060 if raw_categories := payload.get("itemCategories"): 2061 for item in raw_categories: 2062 title = undefined.Undefined 2063 if raw_title := item.get("title"): 2064 if raw_title != typedefs.Unknown: 2065 title = raw_title 2066 if raw_hashes := item.get("itemHashes"): 2067 hashes: collections.Sequence[int] = raw_hashes 2068 2069 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2070 2071 about = undefined.Undefined 2072 if (raw_about := payload["about"]) != typedefs.Unknown: 2073 about = raw_about 2074 2075 status = undefined.Undefined 2076 if (raw_status := payload["status"]) != typedefs.Unknown: 2077 status = raw_status 2078 2079 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2080 if raw_tips := payload.get("tips"): 2081 for raw_tip in raw_tips: 2082 if raw_tip == typedefs.Unknown: 2083 raw_tip = undefined.Undefined 2084 tips.append(raw_tip) 2085 2086 return milestones.MilestoneContent( 2087 about=about, status=status, tips=tips, items=items_categoris 2088 ) 2089 2090 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2091 name = undefined.Undefined 2092 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2093 name = raw_name 2094 2095 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2096 2097 if raw_bungie_user := payload.get("bungieNetUser"): 2098 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2099 2100 return friends.Friend( 2101 net=self._net, 2102 id=int(payload["lastSeenAsMembershipId"]), 2103 name=name, 2104 code=payload.get("bungieGlobalDisplayNameCode"), 2105 relationship=enums.Relationship(payload["relationship"]), 2106 user=bungie_user, 2107 online_status=enums.Presence(payload["onlineStatus"]), 2108 online_title=payload["onlineTitle"], 2109 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2110 ) 2111 2112 def deserialize_friends( 2113 self, payload: typedefs.JSONObject 2114 ) -> collections.Sequence[friends.Friend]: 2115 mut_seq: typing.MutableSequence[friends.Friend] = [] 2116 if raw_friends := payload.get("friends"): 2117 for friend in raw_friends: 2118 mut_seq.append(self.deserialize_friend(friend)) 2119 return mut_seq 2120 2121 def deserialize_friend_requests( 2122 self, payload: typedefs.JSONObject 2123 ) -> friends.FriendRequestView: 2124 incoming: typing.MutableSequence[friends.Friend] = [] 2125 outgoing: typing.MutableSequence[friends.Friend] = [] 2126 2127 if raw_incoming_requests := payload.get("incomingRequests"): 2128 for incoming_request in raw_incoming_requests: 2129 incoming.append(self.deserialize_friend(incoming_request)) 2130 2131 if raw_outgoing_requests := payload.get("outgoingRequests"): 2132 for outgoing_request in raw_outgoing_requests: 2133 outgoing.append(self.deserialize_friend(outgoing_request)) 2134 2135 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing) 2136 2137 def _set_fireteam_fields( 2138 self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None 2139 ) -> fireteams.Fireteam: 2140 activity_type = fireteams.FireteamActivity(payload["activityType"]) 2141 return fireteams.Fireteam( 2142 id=int(payload["fireteamId"]), 2143 group_id=int(payload["groupId"]), 2144 platform=fireteams.FireteamPlatform(payload["platform"]), 2145 is_immediate=payload["isImmediate"], 2146 activity_type=activity_type, 2147 owner_id=int(payload["ownerMembershipId"]), 2148 player_slot_count=payload["playerSlotCount"], 2149 available_player_slots=payload["availablePlayerSlotCount"], 2150 available_alternate_slots=payload["availableAlternateSlotCount"], 2151 title=payload["title"], 2152 date_created=time.clean_date(payload["dateCreated"]), 2153 is_public=payload["isPublic"], 2154 locale=fireteams.FireteamLanguage(payload["locale"]), 2155 is_valid=payload["isValid"], 2156 last_modified=time.clean_date(payload["datePlayerModified"]), 2157 total_results=total_results or 0, 2158 ) 2159 2160 def deserialize_fireteams( 2161 self, payload: typedefs.JSONObject 2162 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2163 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2164 2165 result: list[typedefs.JSONObject] 2166 if not (result := payload["results"]): 2167 return None 2168 for elem in result: 2169 fireteams_.append( 2170 self._set_fireteam_fields( 2171 elem, total_results=int(payload["totalResults"]) 2172 ) 2173 ) 2174 return fireteams_ 2175 2176 def deserialize_fireteam_destiny_users( 2177 self, payload: typedefs.JSONObject 2178 ) -> fireteams.FireteamUser: 2179 destiny_obj = self.deserialize_destiny_membership(payload) 2180 # We could helpers.just return a DestinyMembership object but this is 2181 # missing the fireteam display name and id fields. 2182 return fireteams.FireteamUser( 2183 net=self._net, 2184 id=destiny_obj.id, 2185 code=destiny_obj.code, 2186 icon=destiny_obj.icon, 2187 types=destiny_obj.types, 2188 type=destiny_obj.type, 2189 is_public=destiny_obj.is_public, 2190 crossave_override=destiny_obj.crossave_override, 2191 name=destiny_obj.name, 2192 last_seen_name=destiny_obj.last_seen_name, 2193 fireteam_display_name=payload["FireteamDisplayName"], 2194 fireteam_membership_id=enums.MembershipType( 2195 payload["FireteamMembershipType"] 2196 ), 2197 ) 2198 2199 def deserialize_fireteam_members( 2200 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2201 ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]: 2202 members_: list[fireteams.FireteamMember] = [] 2203 if members := payload.get("Members" if not alternatives else "Alternates"): 2204 for member in members: 2205 bungie_fields = self.deserialize_partial_bungie_user(member) 2206 members_fields = fireteams.FireteamMember( 2207 destiny_user=self.deserialize_fireteam_destiny_users(member), 2208 has_microphone=member["hasMicrophone"], 2209 character_id=int(member["characterId"]), 2210 date_joined=time.clean_date(member["dateJoined"]), 2211 last_platform_invite_date=time.clean_date( 2212 member["lastPlatformInviteAttemptDate"] 2213 ), 2214 last_platform_invite_result=int( 2215 member["lastPlatformInviteAttemptResult"] 2216 ), 2217 net=self._net, 2218 name=bungie_fields.name, 2219 id=bungie_fields.id, 2220 icon=bungie_fields.icon, 2221 is_public=bungie_fields.is_public, 2222 crossave_override=bungie_fields.crossave_override, 2223 types=bungie_fields.types, 2224 type=bungie_fields.type, 2225 ) 2226 members_.append(members_fields) 2227 else: 2228 return None 2229 return members_ 2230 2231 def deserialize_available_fireteams( 2232 self, 2233 data: typedefs.JSONObject, 2234 *, 2235 no_results: bool = False, 2236 ) -> typing.Union[ 2237 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2238 ]: 2239 fireteams_: list[fireteams.AvailableFireteam] = [] 2240 2241 # This needs to be used outside the results 2242 # JSON key. 2243 if no_results is True: 2244 payload = data 2245 2246 if result := payload.get("results"): 2247 2248 for fireteam in result: 2249 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2250 fireteams_fields = fireteams.AvailableFireteam( 2251 id=found_fireteams.id, 2252 group_id=found_fireteams.group_id, 2253 platform=found_fireteams.platform, 2254 activity_type=found_fireteams.activity_type, 2255 is_immediate=found_fireteams.is_immediate, 2256 is_public=found_fireteams.is_public, 2257 is_valid=found_fireteams.is_valid, 2258 owner_id=found_fireteams.owner_id, 2259 player_slot_count=found_fireteams.player_slot_count, 2260 available_player_slots=found_fireteams.available_player_slots, 2261 available_alternate_slots=found_fireteams.available_alternate_slots, 2262 title=found_fireteams.title, 2263 date_created=found_fireteams.date_created, 2264 locale=found_fireteams.locale, 2265 last_modified=found_fireteams.last_modified, 2266 total_results=found_fireteams.total_results, 2267 members=self.deserialize_fireteam_members(payload), 2268 alternatives=self.deserialize_fireteam_members( 2269 payload, alternatives=True 2270 ), 2271 ) 2272 fireteams_.append(fireteams_fields) 2273 if no_results: 2274 return fireteams_fields 2275 return fireteams_ 2276 2277 def deserialize_fireteam_party( 2278 self, payload: typedefs.JSONObject 2279 ) -> fireteams.FireteamParty: 2280 last_destination_hash: typing.Optional[int] = None 2281 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2282 last_destination_hash = int(raw_dest_hash) 2283 2284 return fireteams.FireteamParty( 2285 members=[ 2286 self._deserialize_fireteam_party_member(member) 2287 for member in payload["partyMembers"] 2288 ], 2289 activity=self._deserialize_fireteam_party_current_activity( 2290 payload["currentActivity"] 2291 ), 2292 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2293 last_destination_hash=last_destination_hash, 2294 tracking=payload["tracking"], 2295 ) 2296 2297 def _deserialize_fireteam_party_member( 2298 self, payload: typedefs.JSONObject 2299 ) -> fireteams.FireteamPartyMember: 2300 2301 status = fireteams.FireteamPartyMemberState(payload["status"]) 2302 displayname: undefined.UndefinedOr[str] = undefined.Undefined 2303 if raw_name := payload.get("displayName"): 2304 displayname = raw_name 2305 2306 return fireteams.FireteamPartyMember( 2307 membership_id=int(payload["membershipId"]), 2308 emblem_hash=int(payload["emblemHash"]), 2309 status=status, 2310 display_name=displayname, 2311 ) 2312 2313 def _deserialize_fireteam_party_current_activity( 2314 self, payload: typedefs.JSONObject 2315 ) -> fireteams.FireteamPartyCurrentActivity: 2316 start_date: typing.Optional[datetime.datetime] = None 2317 if raw_start_date := payload.get("startTime"): 2318 start_date = time.clean_date(raw_start_date) 2319 2320 end_date: typing.Optional[datetime.datetime] = None 2321 if raw_end_date := payload.get("endTime"): 2322 end_date = time.clean_date(raw_end_date) 2323 return fireteams.FireteamPartyCurrentActivity( 2324 start_time=start_date, 2325 end_time=end_date, 2326 score=float(payload["score"]), 2327 highest_opposing_score=float(payload["highestOpposingFactionScore"]), 2328 opponenst_count=int(payload["numberOfOpponents"]), 2329 player_count=int(payload["numberOfPlayers"]), 2330 ) 2331 2332 def _deserialize_fireteam_party_settings( 2333 self, payload: typedefs.JSONObject 2334 ) -> fireteams.FireteamPartySettings: 2335 closed_reasons = enums.ClosedReasons(payload["closedReasons"]) 2336 return fireteams.FireteamPartySettings( 2337 open_slots=int(payload["openSlots"]), 2338 privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])), 2339 closed_reasons=closed_reasons, 2340 ) 2341 2342 def deserialize_seasonal_artifact( 2343 self, payload: typedefs.JSONObject 2344 ) -> season.Artifact: 2345 if raw_artifact := payload.get("seasonalArtifact"): 2346 if points := raw_artifact.get("pointProgression"): 2347 points_prog = progressions.Progression( 2348 hash=points["progressionHash"], 2349 level=points["level"], 2350 cap=points["levelCap"], 2351 daily_limit=points["dailyLimit"], 2352 weekly_limit=points["weeklyLimit"], 2353 current_progress=points["currentProgress"], 2354 daily_progress=points["dailyProgress"], 2355 needed=points["progressToNextLevel"], 2356 next_level=points["nextLevelAt"], 2357 ) 2358 2359 if bonus := raw_artifact.get("powerBonusProgression"): 2360 power_bonus_prog = progressions.Progression( 2361 hash=bonus["progressionHash"], 2362 level=bonus["level"], 2363 cap=bonus["levelCap"], 2364 daily_limit=bonus["dailyLimit"], 2365 weekly_limit=bonus["weeklyLimit"], 2366 current_progress=bonus["currentProgress"], 2367 daily_progress=bonus["dailyProgress"], 2368 needed=bonus["progressToNextLevel"], 2369 next_level=bonus["nextLevelAt"], 2370 ) 2371 artifact = season.Artifact( 2372 net=self._net, 2373 hash=raw_artifact["artifactHash"], 2374 power_bonus=raw_artifact["powerBonus"], 2375 acquired_points=raw_artifact["pointsAcquired"], 2376 bonus=power_bonus_prog, 2377 points=points_prog, 2378 ) 2379 return artifact 2380 2381 def deserialize_profile_progression( 2382 self, payload: typedefs.JSONObject 2383 ) -> profile.ProfileProgression: 2384 return profile.ProfileProgression( 2385 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2386 checklist={ 2387 int(check_id): checklists 2388 for check_id, checklists in payload["data"]["checklists"].items() 2389 }, 2390 ) 2391 2392 def deserialize_instanced_item( 2393 self, payload: typedefs.JSONObject 2394 ) -> items.ItemInstance: 2395 damage_type_hash: typing.Optional[int] = None 2396 if raw_damagetype_hash := payload.get("damageTypeHash"): 2397 damage_type_hash = int(raw_damagetype_hash) 2398 2399 required_hashes: typing.Optional[collections.Collection[int]] = None 2400 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2401 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2402 2403 breaker_type: typing.Optional[items.ItemBreakerType] = None 2404 if raw_break_type := payload.get("breakerType"): 2405 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2406 2407 breaker_type_hash: typing.Optional[int] = None 2408 if raw_break_type_hash := payload.get("breakerTypeHash"): 2409 breaker_type_hash = int(raw_break_type_hash) 2410 2411 energy: typing.Optional[items.ItemEnergy] = None 2412 if raw_energy := payload.get("energy"): 2413 energy = self.deserialize_item_energy(raw_energy) 2414 2415 primary_stats = None 2416 if raw_primary_stats := payload.get("primaryStat"): 2417 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2418 2419 return items.ItemInstance( 2420 damage_type=enums.DamageType(int(payload["damageType"])), 2421 damage_type_hash=damage_type_hash, 2422 primary_stat=primary_stats, 2423 item_level=int(payload["itemLevel"]), 2424 quality=int(payload["quality"]), 2425 is_equipped=payload["isEquipped"], 2426 can_equip=payload["canEquip"], 2427 equip_required_level=int(payload["equipRequiredLevel"]), 2428 required_equip_unlock_hashes=required_hashes, 2429 cant_equip_reason=int(payload["cannotEquipReason"]), 2430 breaker_type=breaker_type, 2431 breaker_type_hash=breaker_type_hash, 2432 energy=energy, 2433 ) 2434 2435 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2436 energy_hash: typing.Optional[int] = None 2437 if raw_energy_hash := payload.get("energyTypeHash"): 2438 energy_hash = int(raw_energy_hash) 2439 2440 return items.ItemEnergy( 2441 hash=energy_hash, 2442 type=items.ItemEnergyType(int(payload["energyType"])), 2443 capacity=int(payload["energyCapacity"]), 2444 used_energy=int(payload["energyUsed"]), 2445 unused_energy=int(payload["energyUnused"]), 2446 ) 2447 2448 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2449 perk_hash: typing.Optional[int] = None 2450 if raw_perk_hash := payload.get("perkHash"): 2451 perk_hash = int(raw_perk_hash) 2452 2453 return items.ItemPerk( 2454 hash=perk_hash, 2455 icon=assets.Image(payload["iconPath"]), 2456 is_active=payload["isActive"], 2457 is_visible=payload["visible"], 2458 ) 2459 2460 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2461 plug_hash: typing.Optional[int] = None 2462 if raw_plug_hash := payload.get("plugHash"): 2463 plug_hash = int(raw_plug_hash) 2464 2465 enable_fail_indexes: typing.Optional[list[int]] = None 2466 if raw_indexes := payload.get("enableFailIndexes"): 2467 enable_fail_indexes = [int(index) for index in raw_indexes] 2468 2469 return items.ItemSocket( 2470 plug_hash=plug_hash, 2471 is_enabled=payload["isEnabled"], 2472 enable_fail_indexes=enable_fail_indexes, 2473 is_visible=payload.get("visible"), 2474 ) 2475 2476 def deserialize_item_stats_view( 2477 self, payload: typedefs.JSONObject 2478 ) -> items.ItemStatsView: 2479 return items.ItemStatsView( 2480 stat_hash=payload.get("statHash"), value=payload.get("value") 2481 ) 2482 2483 def deserialize_plug_item_state( 2484 self, payload: typedefs.JSONObject 2485 ) -> items.PlugItemState: 2486 item_hash: typing.Optional[int] = None 2487 if raw_item_hash := payload.get("plugItemHash"): 2488 item_hash = int(raw_item_hash) 2489 2490 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2491 if raw_fail_indexes := payload.get("insertFailIndexes"): 2492 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2493 2494 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2495 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2496 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2497 2498 return items.PlugItemState( 2499 item_hash=item_hash, 2500 insert_fail_indexes=insert_fail_indexes, 2501 enable_fail_indexes=enable_fail_indexes, 2502 is_enabled=payload["enabled"], 2503 can_insert=payload["canInsert"], 2504 )
The base deserialization factory class for all aiobungie objects.
Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
into a aiobungie.crates Python classes.
73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 )
Deserialize a raw JSON Bungie.net user only payload into a user object.
This only returns the Bungie.net user and not the Destiny memberships.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.BungieUser: A Bungie user.
97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.Undefined), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 )
Deserialize a raw JSON of a partial bungieNetUserInfo.
A partial user is a bungie.net user payload with missing information from
the main BungieUser object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PartialBungieUser: A partial bungie user.
114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.Undefined 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") # noqa: W503 130 or "", # noqa: W503 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload.get("applicableMembershipTypes", []) 138 ], 139 )
Deserialize a raw JSON of destinyUserInfo destiny membership information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
141 def deserialize_destiny_memberships( 142 self, data: typedefs.JSONArray 143 ) -> collections.Sequence[user.DestinyMembership]: 144 return [self.deserialize_destiny_membership(membership) for membership in data]
Deserialize a raw JSON payload/array of destinyUserInfo.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
146 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 147 148 primary_membership_id: typing.Optional[int] = None 149 if raw_primary_id := data.get("primaryMembershipId"): 150 primary_membership_id = int(raw_primary_id) 151 152 return user.User( 153 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 154 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 155 primary_membership_id=primary_membership_id, 156 )
Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.User: A user object.
158 def deserialize_searched_user( 159 self, payload: typedefs.JSONObject 160 ) -> user.SearchableDestinyUser: 161 name: undefined.UndefinedOr[str] = undefined.Undefined 162 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 163 raw_name 164 ): 165 name = raw_name 166 167 code: typing.Optional[int] = None 168 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 169 code = int(raw_code) 170 171 bungie_id: typing.Optional[int] = None 172 if raw_bungie_id := payload.get("bungieNetMembershipId"): 173 bungie_id = int(raw_bungie_id) 174 175 return user.SearchableDestinyUser( 176 name=name, 177 code=code, 178 bungie_id=bungie_id, 179 memberships=self.deserialize_destiny_memberships( 180 payload["destinyMemberships"] 181 ), 182 )
Deserialize the results of user search details.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.SearchableDestinyUser: The searched for Destiny 2 membership.
184 def deserialize_user_credentials( 185 self, payload: typedefs.JSONArray 186 ) -> collections.Sequence[user.UserCredentials]: 187 return [ 188 user.UserCredentials( 189 type=enums.CredentialType(int(creds["credentialType"])), 190 display_name=creds["credentialDisplayName"], 191 is_public=creds["isPublic"], 192 self_as_string=creds.get("credentialAsString", undefined.Undefined), 193 ) 194 for creds in payload 195 ]
Deserialize a JSON array of Bungie user credentials.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of user's credentials.
197 @staticmethod 198 def set_themese_attrs( 199 payload: typedefs.JSONArray, / 200 ) -> typing.Collection[user.UserThemes]: 201 return [ 202 user.UserThemes( 203 id=int(entry["userThemeId"]), 204 name=entry["userThemeName"] 205 if "userThemeName" in entry 206 else undefined.Undefined, 207 description=entry["userThemeDescription"] 208 if "userThemeDescription" in entry 209 else undefined.Undefined, 210 ) 211 for entry in payload 212 ]
214 def deserialize_user_themes( 215 self, payload: typedefs.JSONArray 216 ) -> collections.Sequence[user.UserThemes]: 217 return list(self.set_themese_attrs(payload))
Deserialize a raw JSON array of Bungie user themes.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
219 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 220 221 # This is kinda redundant 222 data = payload 223 224 # This is always outside the details. 225 current_user_map: typing.Optional[ 226 collections.Mapping[str, clans.ClanMember] 227 ] = None 228 if raw_current_user_map := payload.get("currentUserMemberMap"): 229 current_user_map = { 230 membership_type: self.deserialize_clan_member(membership) 231 for membership_type, membership in raw_current_user_map.items() 232 } 233 234 try: 235 data = payload["detail"] 236 except KeyError: 237 pass 238 239 id = data["groupId"] 240 name = data["name"] 241 created_at = data["creationDate"] 242 member_count = data["memberCount"] 243 about = data["about"] 244 motto = data["motto"] 245 is_public = data["isPublic"] 246 banner = assets.Image(str(data["bannerPath"])) 247 avatar = assets.Image(str(data["avatarPath"])) 248 tags = data["tags"] 249 type = data["groupType"] 250 251 features = data["features"] 252 features_obj = clans.ClanFeatures( 253 max_members=features["maximumMembers"], 254 max_membership_types=features["maximumMembershipsOfGroupType"], 255 capabilities=features["capabilities"], 256 membership_types=features["membershipTypes"], 257 invite_permissions=features["invitePermissionOverride"], 258 update_banner_permissions=features["updateBannerPermissionOverride"], 259 update_culture_permissions=features["updateCulturePermissionOverride"], 260 join_level=features["joinLevel"], 261 ) 262 263 information: typedefs.JSONObject = data["clanInfo"] 264 progression: collections.Mapping[int, progressions.Progression] = { 265 int(prog_hash): self.deserialize_progressions(prog) 266 for prog_hash, prog in information["d2ClanProgressions"].items() 267 } 268 269 founder: typedefs.NoneOr[clans.ClanMember] = None 270 if raw_founder := payload.get("founder"): 271 founder = self.deserialize_clan_member(raw_founder) 272 273 return clans.Clan( 274 net=self._net, 275 id=int(id), 276 name=name, 277 type=enums.GroupType(type), 278 created_at=time.clean_date(created_at), 279 member_count=member_count, 280 motto=motto, 281 about=about, 282 is_public=is_public, 283 banner=banner, 284 avatar=avatar, 285 tags=tags, 286 features=features_obj, 287 owner=founder, 288 progressions=progression, 289 call_sign=information["clanCallsign"], 290 banner_data=information["clanBannerData"], 291 chat_security=data["chatSecurity"], 292 conversation_id=int(data["conversationId"]), 293 allow_chat=data["allowChat"], 294 theme=data["theme"], 295 current_user_membership=current_user_map, 296 )
Deserialize a raw JSON payload of Bungie clan information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Clan: A clan owner.
298 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 299 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 300 return clans.ClanMember( 301 net=self._net, 302 last_seen_name=destiny_user.last_seen_name, 303 id=destiny_user.id, 304 name=destiny_user.name, 305 icon=destiny_user.icon, 306 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 307 group_id=int(data["groupId"]), 308 joined_at=time.clean_date(data["joinDate"]), 309 types=destiny_user.types, 310 is_public=destiny_user.is_public, 311 type=destiny_user.type, 312 code=destiny_user.code, 313 is_online=data["isOnline"], 314 crossave_override=destiny_user.crossave_override, 315 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 316 if "bungieNetUserInfo" in data 317 else None, 318 member_type=enums.ClanMemberType(int(data["memberType"])), 319 )
Deserialize a JSON payload of a clan member information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ClanMember: A clan member.
321 def deserialize_clan_members( 322 self, data: typedefs.JSONObject, / 323 ) -> iterators.FlatIterator[clans.ClanMember]: 324 return iterators.FlatIterator( 325 [self.deserialize_clan_member(member) for member in data["results"]] 326 )
Deserialize a JSON payload of a clan members information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator of clan members of the deserialized payload.
328 def deserialize_group_member( 329 self, payload: typedefs.JSONObject 330 ) -> clans.GroupMember: 331 member = payload["member"] 332 return clans.GroupMember( 333 net=self._net, 334 join_date=time.clean_date(member["joinDate"]), 335 group_id=int(member["groupId"]), 336 member_type=enums.ClanMemberType(member["memberType"]), 337 is_online=member["isOnline"], 338 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 339 inactive_memberships=payload.get("areAllMembershipsInactive", None), 340 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 341 group=self.deserialize_clan(payload["group"]), 342 )
Deserialize a JSON payload of group information for a member.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.typedefs.NoneOr[aiobungie.crates.GroupMember]: A group member. This can returnNoneif nothing was found.
360 def deserialize_clan_conversations( 361 self, payload: typedefs.JSONArray 362 ) -> collections.Sequence[clans.ClanConversation]: 363 return [self._deserialize_clan_conversation(conv) for conv in payload]
Deserialize a JSON array of a clan conversations information.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of clan conversations of the deserialized payload.
365 def deserialize_app_owner( 366 self, payload: typedefs.JSONObject 367 ) -> application.ApplicationOwner: 368 return application.ApplicationOwner( 369 net=self._net, 370 name=payload.get("bungieGlobalDisplayName", undefined.Undefined), 371 id=int(payload["membershipId"]), 372 type=enums.MembershipType(payload["membershipType"]), 373 icon=assets.Image(str(payload["iconPath"])), 374 is_public=payload["isPublic"], 375 code=payload.get("bungieGlobalDisplayNameCode", None), 376 )
Deserialize a JSON payload of Bungie Developer portal application owner information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.ApplicationOwner: An application owner.
378 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 379 return application.Application( 380 id=int(payload["applicationId"]), 381 name=payload["name"], 382 link=payload["link"], 383 status=payload["status"], 384 redirect_url=payload.get("redirectUrl", None), 385 created_at=time.clean_date(str(payload["creationDate"])), 386 published_at=time.clean_date(str(payload["firstPublished"])), 387 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 388 scope=payload.get("scope", undefined.Undefined), 389 )
Deserialize a JSON payload of Bungie Developer portal application information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.Application: An application.
412 def deserialize_profile( 413 self, payload: typedefs.JSONObject, / 414 ) -> typing.Optional[profile.Profile]: 415 if (raw_profile := payload.get("data")) is None: 416 return None 417 418 payload = raw_profile 419 id = int(payload["userInfo"]["membershipId"]) 420 name = payload["userInfo"]["displayName"] 421 is_public = payload["userInfo"]["isPublic"] 422 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 423 last_played = time.clean_date(str(payload["dateLastPlayed"])) 424 character_ids = [int(cid) for cid in payload["characterIds"]] 425 power_cap = payload["currentSeasonRewardPowerCap"] 426 427 return profile.Profile( 428 id=int(id), 429 name=name, 430 is_public=is_public, 431 type=type, 432 last_played=last_played, 433 character_ids=character_ids, 434 power_cap=power_cap, 435 net=self._net, 436 )
Deserialize a JSON payload of Bungie.net profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
typing.Optional[aiobungie.crates.Profile]: A profile.
438 def deserialize_profile_item( 439 self, payload: typedefs.JSONObject 440 ) -> profile.ProfileItemImpl: 441 442 instance_id: typing.Optional[int] = None 443 if raw_instance_id := payload.get("itemInstanceId"): 444 instance_id = int(raw_instance_id) 445 446 version_number: typing.Optional[int] = None 447 if raw_version := payload.get("versionNumber"): 448 version_number = int(raw_version) 449 450 transfer_status = enums.TransferStatus(payload["transferStatus"]) 451 452 return profile.ProfileItemImpl( 453 net=self._net, 454 hash=payload["itemHash"], 455 quantity=payload["quantity"], 456 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 457 location=enums.ItemLocation(payload["location"]), 458 bucket=payload["bucketHash"], 459 transfer_status=transfer_status, 460 lockable=payload["lockable"], 461 state=enums.ItemState(payload["state"]), 462 dismantel_permissions=payload["dismantlePermission"], 463 is_wrapper=payload["isWrapper"], 464 instance_id=instance_id, 465 version_number=version_number, 466 ornament_id=payload.get("overrideStyleItemHash"), 467 )
Deserialize a JSON payload of a singular profile component item.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ProfileItemImpl: Implementation of a Destiny 2 profile component item.
469 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 470 return records.Objective( 471 net=self._net, 472 hash=payload["objectiveHash"], 473 visible=payload["visible"], 474 complete=payload["complete"], 475 completion_value=payload["completionValue"], 476 progress=payload.get("progress"), 477 destination_hash=payload.get("destinationHash"), 478 activity_hash=payload.get("activityHash"), 479 )
Deserialize a JSON payload of an objective found in a record profile component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.records.Objective: A record objective object.
481 def deserialize_records( 482 self, 483 payload: typedefs.JSONObject, 484 scores: typing.Optional[records.RecordScores] = None, 485 **nodes: int, 486 ) -> records.Record: 487 objectives: typing.Optional[list[records.Objective]] = None 488 interval_objectives: typing.Optional[list[records.Objective]] = None 489 record_state: typedefs.IntAnd[records.RecordState] 490 491 record_state = records.RecordState(payload["state"]) 492 493 if raw_objs := payload.get("objectives"): 494 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 495 496 if raw_interval_objs := payload.get("intervalObjectives"): 497 interval_objectives = [ 498 self.deserialize_objectives(obj) for obj in raw_interval_objs 499 ] 500 501 return records.Record( 502 scores=scores, 503 categories_node_hash=nodes.get("categories_hash", undefined.Undefined), 504 seals_node_hash=nodes.get("seals_hash", undefined.Undefined), 505 state=record_state, 506 objectives=objectives, 507 interval_objectives=interval_objectives, 508 redeemed_count=payload.get("intervalsRedeemedCount", 0), 509 completion_times=payload.get("completedCount", None), 510 reward_visibility=payload.get("rewardVisibilty", None), 511 )
Deserialize a JSON object of a profile record component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload - scores (
typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature ofaiobungie.crates.CharacterRecordwith the record object. As it will always beNonein that object. - **nodes (
int): An int kwargs use to grab the node hashes while deserializing components.
Returns
aiobungie.records.Record: A standard implementation of a profile record component.
513 def deserialize_character_records( 514 self, 515 payload: typedefs.JSONObject, 516 scores: typing.Optional[records.RecordScores] = None, 517 record_hashes: typing.Optional[list[int]] = None, 518 ) -> records.CharacterRecord: 519 520 record = self.deserialize_records(payload, scores) 521 return records.CharacterRecord( 522 scores=scores, 523 categories_node_hash=record.categories_node_hash, 524 seals_node_hash=record.seals_node_hash, 525 state=record.state, 526 objectives=record.objectives, 527 interval_objectives=record.interval_objectives, 528 redeemed_count=payload.get("intervalsRedeemedCount", 0), 529 completion_times=payload.get("completedCount"), 530 reward_visibility=payload.get("rewardVisibilty"), 531 record_hashes=record_hashes or [], 532 )
Deserialize a JSON object of a profile character record component.
This almost does the same this as deserialize_records but
has more fields which can only be found in a character record.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
534 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 535 return character.Dye( 536 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 537 )
Deserialize a JSON payload of a character's dye information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.Dye: Information about a character dye object.
539 def deserialize_character_customization( 540 self, payload: typedefs.JSONObject 541 ) -> character.CustomizationOptions: 542 return character.CustomizationOptions( 543 personality=payload["personality"], 544 face=payload["face"], 545 skin_color=payload["skinColor"], 546 lip_color=payload["lipColor"], 547 eye_color=payload["eyeColor"], 548 hair_colors=payload.get("hairColors", []), 549 feature_colors=payload.get("featureColors", []), 550 decal_color=payload["decalColor"], 551 wear_helmet=payload["wearHelmet"], 552 hair_index=payload["hairIndex"], 553 feature_index=payload["featureIndex"], 554 decal_index=payload["decalIndex"], 555 )
Deserialize a JSON payload of a character customization information found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
557 def deserialize_character_minimal_equipments( 558 self, payload: typedefs.JSONObject 559 ) -> character.MinimalEquipments: 560 dyes = None 561 if raw_dyes := payload.get("dyes"): 562 if raw_dyes: 563 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 564 return character.MinimalEquipments( 565 net=self._net, item_hash=payload["itemHash"], dyes=dyes 566 )
Deserialize a singular JSON peer view of equipment found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
568 def deserialize_character_render_data( 569 self, payload: typedefs.JSONObject, / 570 ) -> character.RenderedData: 571 return character.RenderedData( 572 net=self._net, 573 customization=self.deserialize_character_customization( 574 payload["customization"] 575 ), 576 custom_dyes=[ 577 self.deserialize_character_dye(dye) 578 for dye in payload["customDyes"] 579 if dye 580 ], 581 equipment=[ 582 self.deserialize_character_minimal_equipments(equipment) 583 for equipment in payload["peerView"]["equipment"] 584 ], 585 )
Deserialize a JSON payload of a profile character render data component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.RenderedData: A character rendered data profile component.
587 def deserialize_available_activity( 588 self, payload: typedefs.JSONObject 589 ) -> activity.AvailableActivity: 590 return activity.AvailableActivity( 591 hash=payload["activityHash"], 592 is_new=payload["isNew"], 593 is_completed=payload["isCompleted"], 594 is_visible=payload["isVisible"], 595 display_level=payload.get("displayLevel"), 596 recommended_light=payload.get("recommendedLight"), 597 difficulty=activity.Difficulty(payload["difficultyTier"]), 598 can_join=payload["canJoin"], 599 can_lead=payload["canLead"], 600 )
Deserialize a JSON payload of an available activities.
This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AvailableActivity: An available activity object.
602 def deserialize_character_activity( 603 self, payload: typedefs.JSONObject 604 ) -> activity.CharacterActivity: 605 current_mode: typing.Optional[enums.GameMode] = None 606 if raw_current_mode := payload.get("currentActivityModeType"): 607 current_mode = enums.GameMode(raw_current_mode) 608 609 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 610 if raw_current_modes := payload.get("currentActivityModeTypes"): 611 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 612 613 return activity.CharacterActivity( 614 date_started=time.clean_date(payload["dateActivityStarted"]), 615 current_hash=payload["currentActivityHash"], 616 current_mode_hash=payload["currentActivityModeHash"], 617 current_mode=current_mode, 618 current_mode_hashes=payload.get("currentActivityModeHashes"), 619 current_mode_types=current_mode_types, 620 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 621 last_story_hash=payload["lastCompletedStoryHash"], 622 available_activities=[ 623 self.deserialize_available_activity(activity_) 624 for activity_ in payload["availableActivities"] 625 ], 626 )
Deserialize a JSON payload of character activity profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterActivity: A character activities component object.
628 def deserialize_profile_items( 629 self, payload: typedefs.JSONObject, / 630 ) -> list[profile.ProfileItemImpl]: 631 return [self.deserialize_profile_item(item) for item in payload["items"]]
Deserialize a JSON payload of profile items component information.
This may deserialize profileInventories or profileCurrencies or any
other alternatives.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
typing.Optional[collections.Sequence[aiobungie.crates.ProfileItemImpl]]: A profile component object that contains items of the deserialized payload.
674 def deserialize_progressions( 675 self, payload: typedefs.JSONObject 676 ) -> progressions.Progression: 677 return progressions.Progression( 678 hash=int(payload["progressionHash"]), 679 level=int(payload["level"]), 680 cap=int(payload["levelCap"]), 681 daily_limit=int(payload["dailyLimit"]), 682 weekly_limit=int(payload["weeklyLimit"]), 683 current_progress=int(payload["currentProgress"]), 684 daily_progress=int(payload["dailyProgress"]), 685 needed=int(payload["progressToNextLevel"]), 686 next_level=int(payload["nextLevelAt"]), 687 )
775 def deserialize_milestone( 776 self, payload: typedefs.JSONObject 777 ) -> milestones.Milestone: 778 start_date: typing.Optional[datetime.datetime] = None 779 if raw_start_date := payload.get("startDate"): 780 start_date = time.clean_date(raw_start_date) 781 782 end_date: typing.Optional[datetime.datetime] = None 783 if raw_end_date := payload.get("endDate"): 784 end_date = time.clean_date(raw_end_date) 785 786 rewards: typing.Optional[ 787 collections.Collection[milestones.MilestoneReward] 788 ] = None 789 if raw_rewards := payload.get("rewards"): 790 rewards = [ 791 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 792 ] 793 794 activities: typing.Optional[ 795 collections.Sequence[milestones.MilestoneActivity] 796 ] = None 797 if raw_activities := payload.get("activities"): 798 activities = [ 799 self._deserialize_milestone_activity(active) 800 for active in raw_activities 801 ] 802 803 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 804 if raw_quests := payload.get("availableQuests"): 805 quests = [ 806 self._deserialize_milestone_available_quest(quest) 807 for quest in raw_quests 808 ] 809 810 vendors: typing.Optional[ 811 collections.Sequence[milestones.MilestoneVendor] 812 ] = None 813 if raw_vendors := payload.get("vendors"): 814 vendors = [ 815 milestones.MilestoneVendor( 816 vendor_hash=vendor["vendorHash"], 817 preview_itemhash=vendor.get("previewItemHash"), 818 ) 819 for vendor in raw_vendors 820 ] 821 822 return milestones.Milestone( 823 hash=payload["milestoneHash"], 824 start_date=start_date, 825 end_date=end_date, 826 order=payload["order"], 827 rewards=rewards, 828 available_quests=quests, 829 activities=activities, 830 vendors=vendors, 831 )
885 def deserialize_character_progressions( 886 self, payload: typedefs.JSONObject 887 ) -> character.CharacterProgression: 888 progressions_ = { 889 int(prog_id): self.deserialize_progressions(prog) 890 for prog_id, prog in payload["progressions"].items() 891 } 892 893 factions = { 894 int(faction_id): self._deserialize_factions(faction) 895 for faction_id, faction in payload["factions"].items() 896 } 897 898 milestones_ = { 899 int(milestone_hash): self.deserialize_milestone(milestone) 900 for milestone_hash, milestone in payload["milestones"].items() 901 } 902 903 uninstanced_item_objectives = { 904 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 905 for item_hash, obj in payload["uninstancedItemObjectives"].items() 906 } 907 908 artifact = payload["seasonalArtifact"] 909 seasonal_artifact = season.CharacterScopedArtifact( 910 hash=artifact["artifactHash"], 911 points_used=artifact["pointsUsed"], 912 reset_count=artifact["resetCount"], 913 tiers=[ 914 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 915 ], 916 ) 917 checklists = payload["checklists"] 918 919 return character.CharacterProgression( 920 progressions=progressions_, 921 factions=factions, 922 checklists=checklists, 923 milestones=milestones_, 924 seasonal_artifact=seasonal_artifact, 925 uninstanced_item_objectives=uninstanced_item_objectives, 926 )
928 def deserialize_character_progressions_mapping( 929 self, payload: typedefs.JSONObject 930 ) -> collections.Mapping[int, character.CharacterProgression]: 931 character_progressions: collections.Mapping[ 932 int, character.CharacterProgression 933 ] = {} 934 for char_id, data in payload["data"].items(): 935 # A little hack to stop mypy complaining about Mapping <-> dict 936 character_progressions[int(char_id)] = self.deserialize_character_progressions(data) # type: ignore[index] 937 return character_progressions
939 def deserialize_characters_records( 940 self, 941 payload: typedefs.JSONObject, 942 ) -> collections.Mapping[int, records.CharacterRecord]: 943 944 return { 945 int(rec_id): self.deserialize_character_records( 946 rec, record_hashes=payload.get("featuredRecordHashes") 947 ) 948 for rec_id, rec in payload["records"].items() 949 }
951 def deserialize_profile_records( 952 self, payload: typedefs.JSONObject 953 ) -> collections.Mapping[int, records.Record]: 954 raw_profile_records = payload["data"] 955 scores = records.RecordScores( 956 current_score=raw_profile_records["score"], 957 legacy_score=raw_profile_records["legacyScore"], 958 lifetime_score=raw_profile_records["lifetimeScore"], 959 ) 960 return { 961 int(record_id): self.deserialize_records( 962 record, 963 scores, 964 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 965 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 966 ) 967 for record_id, record in raw_profile_records["records"].items() 968 }
1005 def deserialize_craftables_component( 1006 self, payload: typedefs.JSONObject 1007 ) -> components.CraftablesComponent: 1008 return components.CraftablesComponent( 1009 net=self._net, 1010 craftables={ 1011 int(item_id): self._deserialize_craftable_item(item) 1012 for item_id, item in payload["craftables"].items() 1013 if item is not None 1014 }, 1015 crafting_root_node_hash=payload["craftingRootNodeHash"], 1016 )
1018 def deserialize_components( # noqa: C901 Too complex. 1019 self, payload: typedefs.JSONObject 1020 ) -> components.Component: 1021 1022 profile_: typing.Optional[profile.Profile] = None 1023 if raw_profile := payload.get("profile"): 1024 profile_ = self.deserialize_profile(raw_profile) 1025 1026 profile_progression: typing.Optional[profile.ProfileProgression] = None 1027 if raw_profile_progression := payload.get("profileProgression"): 1028 profile_progression = self.deserialize_profile_progression( 1029 raw_profile_progression 1030 ) 1031 1032 profile_currencies: typing.Optional[ 1033 collections.Sequence[profile.ProfileItemImpl] 1034 ] = None 1035 if raw_profile_currencies := payload.get("profileCurrencies"): 1036 if "data" in raw_profile_currencies: 1037 profile_currencies = self.deserialize_profile_items( 1038 raw_profile_currencies["data"] 1039 ) 1040 1041 profile_inventories: typing.Optional[ 1042 collections.Sequence[profile.ProfileItemImpl] 1043 ] = None 1044 if raw_profile_inventories := payload.get("profileInventory"): 1045 if "data" in raw_profile_inventories: 1046 profile_inventories = self.deserialize_profile_items( 1047 raw_profile_inventories["data"] 1048 ) 1049 1050 profile_records: typing.Optional[ 1051 collections.Mapping[int, records.Record] 1052 ] = None 1053 1054 if raw_profile_records_ := payload.get("profileRecords"): 1055 profile_records = self.deserialize_profile_records(raw_profile_records_) 1056 1057 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1058 if raw_characters := payload.get("characters"): 1059 characters = self.deserialize_characters(raw_characters) 1060 1061 character_records: typing.Optional[ 1062 collections.Mapping[int, records.CharacterRecord] 1063 ] = None 1064 1065 if raw_character_records := payload.get("characterRecords"): 1066 # Had to do it in two steps.. 1067 to_update: typedefs.JSONObject = {} 1068 for _, data in raw_character_records["data"].items(): 1069 for record_id, record in data.items(): 1070 to_update[record_id] = record 1071 1072 character_records = { 1073 int(rec_id): self.deserialize_character_records( 1074 rec, record_hashes=to_update.get("featuredRecordHashes") 1075 ) 1076 for rec_id, rec in to_update["records"].items() 1077 } 1078 1079 character_equipments: typing.Optional[ 1080 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1081 ] = None 1082 if raw_character_equips := payload.get("characterEquipment"): 1083 character_equipments = self.deserialize_character_equipments( 1084 raw_character_equips 1085 ) 1086 1087 character_inventories: typing.Optional[ 1088 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1089 ] = None 1090 if raw_character_inventories := payload.get("characterInventories"): 1091 if "data" in raw_character_inventories: 1092 character_inventories = self.deserialize_character_equipments( 1093 raw_character_inventories 1094 ) 1095 1096 character_activities: typing.Optional[ 1097 collections.Mapping[int, activity.CharacterActivity] 1098 ] = None 1099 if raw_char_acts := payload.get("characterActivities"): 1100 character_activities = self.deserialize_character_activities(raw_char_acts) 1101 1102 character_render_data: typing.Optional[ 1103 collections.Mapping[int, character.RenderedData] 1104 ] = None 1105 if raw_character_render_data := payload.get("characterRenderData"): 1106 character_render_data = self.deserialize_characters_render_data( 1107 raw_character_render_data 1108 ) 1109 1110 character_progressions: typing.Optional[ 1111 collections.Mapping[int, character.CharacterProgression] 1112 ] = None 1113 1114 if raw_character_progressions := payload.get("characterProgressions"): 1115 character_progressions = self.deserialize_character_progressions_mapping( 1116 raw_character_progressions 1117 ) 1118 1119 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1120 if raw_profile_string_vars := payload.get("profileStringVariables"): 1121 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1122 1123 character_string_vars: typing.Optional[ 1124 collections.Mapping[int, collections.Mapping[int, int]] 1125 ] = None 1126 if raw_character_string_vars := payload.get("characterStringVariables"): 1127 character_string_vars = { 1128 int(char_id): data["integerValuesByHash"] 1129 for char_id, data in raw_character_string_vars["data"].items() 1130 } 1131 1132 metrics: typing.Optional[ 1133 collections.Sequence[ 1134 collections.Mapping[ 1135 int, tuple[bool, typing.Optional[records.Objective]] 1136 ] 1137 ] 1138 ] = None 1139 root_node_hash: typing.Optional[int] = None 1140 1141 if raw_metrics := payload.get("metrics"): 1142 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1143 metrics = [ 1144 { 1145 int(metrics_hash): ( 1146 data["invisible"], 1147 self.deserialize_objectives(data["objectiveProgress"]) 1148 if "objectiveProgress" in data 1149 else None, 1150 ) 1151 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1152 } 1153 ] 1154 transitory: typing.Optional[fireteams.FireteamParty] = None 1155 if raw_transitory := payload.get("profileTransitoryData"): 1156 if "data" in raw_transitory: 1157 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1158 1159 item_components: typing.Optional[components.ItemsComponent] = None 1160 if raw_item_components := payload.get("itemComponents"): 1161 item_components = self.deserialize_items_component(raw_item_components) 1162 1163 profile_plugsets: typing.Optional[ 1164 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1165 ] = None 1166 1167 if raw_profile_plugs := payload.get("profilePlugSets"): 1168 profile_plugsets = { 1169 int(index): [self.deserialize_plug_item_state(state) for state in data] 1170 for index, data in raw_profile_plugs["data"]["plugs"].items() 1171 } 1172 1173 character_plugsets: typing.Optional[ 1174 collections.Mapping[ 1175 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1176 ] 1177 ] = None 1178 if raw_char_plugsets := payload.get("characterPlugSets"): 1179 character_plugsets = { 1180 int(char_id): { 1181 int(index): [ 1182 self.deserialize_plug_item_state(state) for state in data 1183 ] 1184 for index, data in inner["plugs"].items() 1185 } 1186 for char_id, inner in raw_char_plugsets["data"].items() 1187 } 1188 1189 character_collectibles: typing.Optional[ 1190 collections.Mapping[int, items.Collectible] 1191 ] = None 1192 if raw_character_collectibles := payload.get("characterCollectibles"): 1193 character_collectibles = { 1194 int(char_id): self._deserialize_collectible(data) 1195 for char_id, data in raw_character_collectibles["data"].items() 1196 } 1197 1198 profile_collectibles: typing.Optional[items.Collectible] = None 1199 if raw_profile_collectibles := payload.get("profileCollectibles"): 1200 profile_collectibles = self._deserialize_collectible( 1201 raw_profile_collectibles["data"] 1202 ) 1203 1204 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1205 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1206 profile_nodes = { 1207 int(node_hash): self._deserialize_node(node) 1208 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1209 } 1210 1211 character_nodes: typing.Optional[ 1212 collections.Mapping[int, collections.Mapping[int, records.Node]] 1213 ] = None 1214 if raw_character_nodes := payload.get("characterPresentationNodes"): 1215 character_nodes = { 1216 int(char_id): { 1217 int(node_hash): self._deserialize_node(node) 1218 for node_hash, node in each_character["nodes"].items() 1219 } 1220 for char_id, each_character in raw_character_nodes["data"].items() 1221 } 1222 1223 platform_silver: typing.Optional[ 1224 collections.Mapping[str, profile.ProfileItemImpl] 1225 ] = None 1226 if raw_platform_silver := payload.get("platformSilver"): 1227 if "data" in raw_platform_silver: 1228 platform_silver = { 1229 platform_name: self.deserialize_profile_item(item) 1230 for platform_name, item in raw_platform_silver["data"][ 1231 "platformSilver" 1232 ].items() 1233 } 1234 1235 character_currency_lookups: typing.Optional[ 1236 collections.Mapping[int, collections.Sequence[items.Currency]] 1237 ] = None 1238 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1239 if "data" in raw_char_lookups: 1240 character_currency_lookups = { 1241 int(char_id): self._deserialize_currencies(currencie) 1242 for char_id, currencie in raw_char_lookups["data"].items() 1243 } 1244 1245 character_craftables: typing.Optional[ 1246 collections.Mapping[int, components.CraftablesComponent] 1247 ] = None 1248 if raw_character_craftables := payload.get("characterCraftables"): 1249 1250 if "data" in raw_character_craftables: 1251 character_craftables = { 1252 int(char_id): self.deserialize_craftables_component(craftable) 1253 for char_id, craftable in raw_character_craftables["data"].items() 1254 } 1255 1256 return components.Component( 1257 profiles=profile_, 1258 profile_progression=profile_progression, 1259 profile_currencies=profile_currencies, 1260 profile_inventories=profile_inventories, 1261 profile_records=profile_records, 1262 characters=characters, 1263 character_records=character_records, 1264 character_equipments=character_equipments, 1265 character_inventories=character_inventories, 1266 character_activities=character_activities, 1267 character_render_data=character_render_data, 1268 character_progressions=character_progressions, 1269 profile_string_variables=profile_string_vars, 1270 character_string_variables=character_string_vars, 1271 metrics=metrics, 1272 root_node_hash=root_node_hash, 1273 transitory=transitory, 1274 item_components=item_components, 1275 profile_plugsets=profile_plugsets, 1276 character_plugsets=character_plugsets, 1277 character_collectibles=character_collectibles, 1278 profile_collectibles=profile_collectibles, 1279 profile_nodes=profile_nodes, 1280 character_nodes=character_nodes, 1281 platform_silver=platform_silver, 1282 character_currency_lookups=character_currency_lookups, 1283 character_craftables=character_craftables, 1284 )
Deserialize a JSON payload of Bungie.net profile components information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Component: A component implementation that includes all other components of the deserialized payload.
1286 def deserialize_items_component( 1287 self, payload: typedefs.JSONObject 1288 ) -> components.ItemsComponent: 1289 instances: typing.Optional[ 1290 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1291 ] = None 1292 if raw_instances := payload.get("instances"): 1293 instances = [ 1294 { 1295 int(ins_id): self.deserialize_instanced_item(item) 1296 for ins_id, item in raw_instances["data"].items() 1297 } 1298 ] 1299 1300 render_data: typing.Optional[ 1301 collections.Mapping[int, tuple[bool, dict[int, int]]] 1302 ] = None 1303 if raw_render_data := payload.get("renderData"): 1304 render_data = { 1305 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1306 for ins_id, data in raw_render_data["data"].items() 1307 } 1308 1309 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1310 if raw_stats := payload.get("stats"): 1311 builder: collections.Mapping[int, items.ItemStatsView] = {} 1312 for ins_id, stat in raw_stats["data"].items(): 1313 for _, items_ in stat.items(): 1314 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1315 stats = builder 1316 1317 sockets: typing.Optional[ 1318 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1319 ] = None 1320 if raw_sockets := payload.get("sockets"): 1321 sockets = { 1322 int(ins_id): [ 1323 self.deserialize_item_socket(socket) for socket in item["sockets"] 1324 ] 1325 for ins_id, item in raw_sockets["data"].items() 1326 } 1327 1328 objeectives: typing.Optional[ 1329 collections.Mapping[int, collections.Sequence[records.Objective]] 1330 ] = None 1331 if raw_objectives := payload.get("objectives"): 1332 objeectives = { 1333 int(ins_id): [self.deserialize_objectives(objective)] 1334 for ins_id, data in raw_objectives["data"].items() 1335 for objective in data["objectives"] 1336 } 1337 1338 perks: typing.Optional[ 1339 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1340 ] = None 1341 if raw_perks := payload.get("perks"): 1342 perks = { 1343 int(ins_id): [ 1344 self.deserialize_item_perk(perk) for perk in item["perks"] 1345 ] 1346 for ins_id, item in raw_perks["data"].items() 1347 } 1348 1349 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1350 if raw_plug_states := payload.get("plugStates"): 1351 pending_states: list[items.PlugItemState] = [] 1352 for _, plug in raw_plug_states["data"].items(): 1353 pending_states.append(self.deserialize_plug_item_state(plug)) 1354 plug_states = pending_states 1355 1356 reusable_plugs: typing.Optional[ 1357 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1358 ] = None 1359 if raw_re_plugs := payload.get("reusablePlugs"): 1360 reusable_plugs = { 1361 int(ins_id): [ 1362 self.deserialize_plug_item_state(state) for state in inner 1363 ] 1364 for ins_id, plug in raw_re_plugs["data"].items() 1365 for inner in list(plug["plugs"].values()) 1366 } 1367 1368 plug_objectives: typing.Optional[ 1369 collections.Mapping[ 1370 int, collections.Mapping[int, collections.Collection[records.Objective]] 1371 ] 1372 ] = None 1373 if raw_plug_objectives := payload.get("plugObjectives"): 1374 plug_objectives = { 1375 int(ins_id): { 1376 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1377 for obj_hash, objs in inner["objectivesPerPlug"].items() 1378 } 1379 for ins_id, inner in raw_plug_objectives["data"].items() 1380 } 1381 1382 return components.ItemsComponent( 1383 sockets=sockets, 1384 stats=stats, 1385 render_data=render_data, 1386 instances=instances, 1387 objectives=objeectives, 1388 perks=perks, 1389 plug_states=plug_states, 1390 reusable_plugs=reusable_plugs, 1391 plug_objectives=plug_objectives, 1392 )
Deserialize a JSON objects within the itemComponents key.`
1394 def deserialize_character_component( # type: ignore[call-arg] 1395 self, payload: typedefs.JSONObject 1396 ) -> components.CharacterComponent: 1397 1398 character_: typing.Optional[character.Character] = None 1399 if raw_singuler_character := payload.get("character"): 1400 character_ = self.deserialize_character(raw_singuler_character["data"]) 1401 1402 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1403 if raw_inventory := payload.get("inventory"): 1404 if "data" in raw_inventory: 1405 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1406 1407 activities: typing.Optional[activity.CharacterActivity] = None 1408 if raw_activities := payload.get("activities"): 1409 activities = self.deserialize_character_activity(raw_activities["data"]) 1410 1411 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1412 if raw_equipments := payload.get("equipment"): 1413 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1414 1415 progressions_: typing.Optional[character.CharacterProgression] = None 1416 if raw_progressions := payload.get("progressions"): 1417 progressions_ = self.deserialize_character_progressions( 1418 raw_progressions["data"] 1419 ) 1420 1421 render_data: typing.Optional[character.RenderedData] = None 1422 if raw_render_data := payload.get("renderData"): 1423 render_data = self.deserialize_character_render_data( 1424 raw_render_data["data"] 1425 ) 1426 1427 character_records: typing.Optional[ 1428 collections.Mapping[int, records.CharacterRecord] 1429 ] = None 1430 if raw_char_records := payload.get("records"): 1431 character_records = self.deserialize_characters_records( 1432 raw_char_records["data"] 1433 ) 1434 1435 item_components: typing.Optional[components.ItemsComponent] = None 1436 if raw_item_components := payload.get("itemComponents"): 1437 item_components = self.deserialize_items_component(raw_item_components) 1438 1439 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1440 if raw_nodes := payload.get("presentationNodes"): 1441 nodes = { 1442 int(node_hash): self._deserialize_node(node) 1443 for node_hash, node in raw_nodes["data"]["nodes"].items() 1444 } 1445 1446 collectibles: typing.Optional[items.Collectible] = None 1447 if raw_collectibles := payload.get("collectibles"): 1448 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1449 1450 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1451 if raw_currencies := payload.get("currencyLookups"): 1452 if "data" in raw_currencies: 1453 currency_lookups = self._deserialize_currencies(raw_currencies) 1454 1455 return components.CharacterComponent( 1456 activities=activities, 1457 equipment=equipment, 1458 inventory=inventory, 1459 progressions=progressions_, 1460 render_data=render_data, 1461 character=character_, 1462 character_records=character_records, 1463 profile_records=None, 1464 item_components=item_components, 1465 currency_lookups=currency_lookups, 1466 collectibles=collectibles, 1467 nodes=nodes, 1468 )
Deserialize a JSON payload of Destiny 2 character component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterComponent: A character component.
1496 def deserialize_inventory_results( 1497 self, payload: typedefs.JSONObject 1498 ) -> iterators.FlatIterator[entity.SearchableEntity]: 1499 suggested_words: list[str] = payload["suggestedWords"] 1500 1501 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1502 return s if not typedefs.is_unknown(s) else undefined.Undefined 1503 1504 return iterators.FlatIterator( 1505 [ 1506 entity.SearchableEntity( 1507 net=self._net, 1508 hash=data["hash"], 1509 entity_type=data["entityType"], 1510 weight=data["weight"], 1511 suggested_words=suggested_words, 1512 name=data["displayProperties"]["name"], 1513 has_icon=data["displayProperties"]["hasIcon"], 1514 description=_check_unknown( 1515 data["displayProperties"]["description"] 1516 ), 1517 icon=assets.Image(data["displayProperties"]["icon"]), 1518 ) 1519 for data in payload["results"]["results"] 1520 ] 1521 )
Deserialize results of searched Destiny2 entities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]: An iterator over the found searched entities.
1550 def deserialize_inventory_entity( # noqa: C901 Too complex. 1551 self, payload: typedefs.JSONObject, / 1552 ) -> entity.InventoryEntity: 1553 1554 props = self._set_entity_attrs(payload) 1555 objects = self._deserialize_inventory_item_objects(payload) 1556 1557 collectible_hash: typing.Optional[int] = None 1558 if raw_collectible_hash := payload.get("collectibleHash"): 1559 collectible_hash = int(raw_collectible_hash) 1560 1561 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1562 if raw_second_icon := payload.get("secondaryIcon"): 1563 secondary_icon = assets.Image(raw_second_icon) 1564 1565 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1566 if raw_second_overlay := payload.get("secondaryOverlay"): 1567 secondary_overlay = assets.Image(raw_second_overlay) 1568 1569 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1570 if raw_second_special := payload.get("secondarySpecial"): 1571 secondary_special = assets.Image(raw_second_special) 1572 1573 screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1574 if raw_screenshot := payload.get("screenshot"): 1575 screenshot = assets.Image(raw_screenshot) 1576 1577 watermark_icon: typing.Optional[assets.Image] = None 1578 if raw_watermark_icon := payload.get("iconWatermark"): 1579 watermark_icon = assets.Image(raw_watermark_icon) 1580 1581 watermark_shelved: typing.Optional[assets.Image] = None 1582 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1583 watermark_shelved = assets.Image(raw_watermark_shelved) 1584 1585 about: undefined.UndefinedOr[str] = undefined.Undefined 1586 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1587 raw_about 1588 ): 1589 about = raw_about 1590 1591 ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined 1592 if ( 1593 raw_ui_style := payload.get("uiItemDisplayStyle") 1594 ) and not typedefs.is_unknown(raw_ui_style): 1595 ui_item_style = raw_ui_style 1596 1597 tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined 1598 if ( 1599 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1600 ) and not typedefs.is_unknown(raw_tier_and_name): 1601 tier_and_name = raw_tier_and_name 1602 1603 type_name: undefined.UndefinedOr[str] = undefined.Undefined 1604 if ( 1605 raw_type_name := payload.get("itemTypeDisplayName") 1606 ) and not typedefs.is_unknown(raw_type_name): 1607 type_name = raw_type_name 1608 1609 display_source: undefined.UndefinedOr[str] = undefined.Undefined 1610 if ( 1611 raw_display_source := payload.get("displaySource") 1612 ) and not typedefs.is_unknown(raw_display_source): 1613 display_source = raw_display_source 1614 1615 lorehash: typing.Optional[int] = None 1616 if raw_lore_hash := payload.get("loreHash"): 1617 lorehash = int(raw_lore_hash) 1618 1619 summary_hash: typing.Optional[int] = None 1620 if raw_summary_hash := payload.get("summaryItemHash"): 1621 summary_hash = raw_summary_hash 1622 1623 breaker_type_hash: typing.Optional[int] = None 1624 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1625 breaker_type_hash = int(raw_breaker_type_hash) 1626 1627 damage_types: typing.Optional[collections.Sequence[int]] = None 1628 if raw_damage_types := payload.get("damageTypes"): 1629 damage_types = [int(type_) for type_ in raw_damage_types] 1630 1631 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1632 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1633 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1634 1635 default_damagetype_hash: typing.Optional[int] = None 1636 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1637 default_damagetype_hash = int(raw_defaultdmg_hash) 1638 1639 emblem_objective_hash: typing.Optional[int] = None 1640 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1641 emblem_objective_hash = int(raw_emblem_obj_hash) 1642 1643 tier_type: typing.Optional[enums.TierType] = None 1644 tier: typing.Optional[enums.ItemTier] = None 1645 bucket_hash: typing.Optional[int] = None 1646 recovery_hash: typing.Optional[int] = None 1647 tier_name: undefined.UndefinedOr[str] = undefined.Undefined 1648 isinstance_item: bool = False 1649 expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined 1650 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined 1651 suppress_expiration: bool = False 1652 max_stack_size: typing.Optional[int] = None 1653 stack_label: undefined.UndefinedOr[str] = undefined.Undefined 1654 1655 if inventory := payload.get("inventory"): 1656 tier_type = enums.TierType(int(inventory["tierType"])) 1657 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1658 bucket_hash = int(inventory["bucketTypeHash"]) 1659 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1660 tier_name = inventory["tierTypeName"] 1661 isinstance_item = inventory["isInstanceItem"] 1662 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1663 max_stack_size = int(inventory["maxStackSize"]) 1664 1665 try: 1666 stack_label = inventory["stackUniqueLabel"] 1667 except KeyError: 1668 pass 1669 1670 return entity.InventoryEntity( 1671 net=self._net, 1672 collectible_hash=collectible_hash, 1673 name=props.name, 1674 about=about, 1675 emblem_objective_hash=emblem_objective_hash, 1676 suppress_expiration=suppress_expiration, 1677 max_stack_size=max_stack_size, 1678 stack_label=stack_label, 1679 tier=tier, 1680 tier_type=tier_type, 1681 tier_name=tier_name, 1682 bucket_hash=bucket_hash, 1683 recovery_bucket_hash=recovery_hash, 1684 isinstance_item=isinstance_item, 1685 expire_in_orbit_message=expire_in_orbit_message, 1686 expiration_tooltip=expire_tool_tip, 1687 lore_hash=lorehash, 1688 type_and_tier_name=tier_and_name, 1689 summary_hash=summary_hash, 1690 ui_display_style=ui_item_style, 1691 type_name=type_name, 1692 breaker_type_hash=breaker_type_hash, 1693 description=props.description, 1694 display_source=display_source, 1695 hash=props.hash, 1696 damage_types=damage_types, 1697 index=props.index, 1698 icon=props.icon, 1699 has_icon=props.has_icon, 1700 screenshot=screenshot, 1701 watermark_icon=watermark_icon, 1702 watermark_shelved=watermark_shelved, 1703 secondary_icon=secondary_icon, 1704 secondary_overlay=secondary_overlay, 1705 secondary_special=secondary_special, 1706 type=enums.ItemType(int(payload["itemType"])), 1707 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1708 trait_ids=[trait for trait in payload.get("traitIds", [])], 1709 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1710 item_class=enums.Class(int(payload["classType"])), 1711 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1712 breaker_type=int(payload["breakerType"]), 1713 default_damagetype=int(payload["defaultDamageType"]), 1714 default_damagetype_hash=default_damagetype_hash, 1715 damagetype_hashes=damagetype_hashes, 1716 tooltip_notifications=payload["tooltipNotifications"], 1717 not_transferable=payload["nonTransferrable"], 1718 allow_actions=payload["allowActions"], 1719 is_equippable=payload["equippable"], 1720 objects=objects, 1721 background_colors=payload.get("backgroundColor", {}), 1722 season_hash=payload.get("seasonHash"), 1723 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1724 )
Deserialize a JSON payload of an inventory entity item information.
This can be any item from DestinyInventoryItemDefinition definition.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.InventoryEntity: An entity item.
1726 def deserialize_objective_entity( 1727 self, payload: typedefs.JSONObject, / 1728 ) -> entity.ObjectiveEntity: 1729 props = self._set_entity_attrs(payload) 1730 return entity.ObjectiveEntity( 1731 net=self._net, 1732 hash=props.hash, 1733 index=props.index, 1734 description=props.description, 1735 name=props.name, 1736 has_icon=props.has_icon, 1737 icon=props.icon, 1738 unlock_value_hash=payload["unlockValueHash"], 1739 completion_value=payload["completionValue"], 1740 scope=entity.GatingScope(int(payload["scope"])), 1741 location_hash=payload["locationHash"], 1742 allowed_negative_value=payload["allowNegativeValue"], 1743 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1744 counting_downward=payload["isCountingDownward"], 1745 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1746 progress_description=payload["progressDescription"], 1747 perks=payload["perks"], 1748 stats=payload["stats"], 1749 minimum_visibility=payload["minimumVisibilityThreshold"], 1750 allow_over_completion=payload["allowOvercompletion"], 1751 show_value_style=payload["showValueOnComplete"], 1752 display_only_objective=payload["isDisplayOnlyObjective"], 1753 complete_value_style=entity.ValueUIStyle( 1754 int(payload["completedValueStyle"]) 1755 ), 1756 progress_value_style=entity.ValueUIStyle( 1757 int(payload["inProgressValueStyle"]) 1758 ), 1759 ui_label=payload["uiLabel"], 1760 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1761 )
Deserialize a JSON payload of an objective entity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity.
1789 def deserialize_activity( 1790 self, 1791 payload: typedefs.JSONObject, 1792 /, 1793 ) -> activity.Activity: 1794 period = time.clean_date(payload["period"]) 1795 details = payload["activityDetails"] 1796 ref_id = int(details["referenceId"]) 1797 instance_id = int(details["instanceId"]) 1798 mode = enums.GameMode(details["mode"]) 1799 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1800 is_private = details["isPrivate"] 1801 membership_type = enums.MembershipType(int(details["membershipType"])) 1802 1803 # Since we're using the same fields for post activity method 1804 # this check is required since post activity doesn't values values 1805 values = self._deserialize_activity_values(payload["values"]) 1806 1807 return activity.Activity( 1808 net=self._net, 1809 hash=ref_id, 1810 instance_id=instance_id, 1811 mode=mode, 1812 modes=modes, 1813 is_private=is_private, 1814 membership_type=membership_type, 1815 occurred_at=period, 1816 values=values, 1817 )
Deserialize a JSON payload of an activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Activity: An activity.
1819 def deserialize_activities( 1820 self, payload: typedefs.JSONObject 1821 ) -> iterators.FlatIterator[activity.Activity]: 1822 return iterators.FlatIterator( 1823 [ 1824 self.deserialize_activity(activity_) 1825 for activity_ in payload["activities"] 1826 ] 1827 )
Deserialize a JSON payload of an array of activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: Am iterator over activity objects of the deserialized payload.
1829 def deserialize_extended_weapon_values( 1830 self, payload: typedefs.JSONObject 1831 ) -> activity.ExtendedWeaponValues: 1832 1833 assists: typing.Optional[int] = None 1834 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1835 assists = raw_assists["basic"]["value"] 1836 assists_damage: typing.Optional[int] = None 1837 1838 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1839 assists_damage = raw_assists_damage["basic"]["value"] 1840 1841 return activity.ExtendedWeaponValues( 1842 reference_id=int(payload["referenceId"]), 1843 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1844 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1845 "value" 1846 ], 1847 assists=assists, 1848 assists_damage=assists_damage, 1849 precision_kills_percentage=( 1850 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1851 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1852 "displayValue" 1853 ], 1854 ), 1855 )
Deserialize values of extended weapons JSON object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ExtendedWeaponValues: Information about an extended weapon values.
1878 def deserialize_post_activity_player( 1879 self, payload: typedefs.JSONObject, / 1880 ) -> activity.PostActivityPlayer: 1881 player = payload["player"] 1882 1883 class_hash: typedefs.NoneOr[int] = None 1884 if (class_hash := player.get("classHash")) is not None: 1885 class_hash = class_hash 1886 1887 race_hash: typedefs.NoneOr[int] = None 1888 if (race_hash := player.get("raceHash")) is not None: 1889 race_hash = race_hash 1890 1891 gender_hash: typedefs.NoneOr[int] = None 1892 if (gender_hash := player.get("genderHash")) is not None: 1893 gender_hash = gender_hash 1894 1895 character_class: undefined.UndefinedOr[str] = undefined.Undefined 1896 if ( 1897 character_class := player.get("characterClass") 1898 ) and not typedefs.is_unknown(character_class): 1899 character_class = character_class 1900 1901 character_level: typedefs.NoneOr[int] = None 1902 if (character_level := player.get("characterLevel")) is not None: 1903 character_level = character_level 1904 1905 return activity.PostActivityPlayer( 1906 standing=int(payload["standing"]), 1907 score=int(payload["score"]["basic"]["value"]), 1908 character_id=payload["characterId"], 1909 destiny_user=self.deserialize_destiny_membership( 1910 player["destinyUserInfo"] 1911 ), 1912 character_class=character_class, 1913 character_level=character_level, 1914 race_hash=race_hash, 1915 gender_hash=gender_hash, 1916 class_hash=class_hash, 1917 light_level=int(player["lightLevel"]), 1918 emblem_hash=int(player["emblemHash"]), 1919 values=self._deserialize_activity_values(payload["values"]), 1920 extended_values=self._deserialize_extended_values(payload["extended"]), 1921 )
Deserialize a JSON payload of a post activity player information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivityPlayer: A post activity player object.
1933 def deserialize_post_activity( 1934 self, payload: typedefs.JSONObject 1935 ) -> activity.PostActivity: 1936 period = time.clean_date(payload["period"]) 1937 details = payload["activityDetails"] 1938 ref_id = int(details["referenceId"]) 1939 instance_id = int(details["instanceId"]) 1940 mode = enums.GameMode(details["mode"]) 1941 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1942 is_private = details["isPrivate"] 1943 membership_type = enums.MembershipType(int(details["membershipType"])) 1944 return activity.PostActivity( 1945 net=self._net, 1946 hash=ref_id, 1947 membership_type=membership_type, 1948 instance_id=instance_id, 1949 mode=mode, 1950 modes=modes, 1951 is_private=is_private, 1952 occurred_at=period, 1953 starting_phase=int(payload["startingPhaseIndex"]), 1954 players=[ 1955 self.deserialize_post_activity_player(player) 1956 for player in payload["entries"] 1957 ], 1958 teams=[ 1959 self._deserialize_post_activity_team(team) for team in payload["teams"] 1960 ], 1961 )
Deserialize a JSON payload of a post activity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivity: A post activity object.
1999 def deserialize_aggregated_activity( 2000 self, payload: typedefs.JSONObject 2001 ) -> activity.AggregatedActivity: 2002 return activity.AggregatedActivity( 2003 hash=int(payload["activityHash"]), 2004 values=self._deserialize_aggregated_activity_values(payload["values"]), 2005 )
Deserialize a JSON payload of an aggregated activity.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AggregatedActivity: An aggregated activity object.
2007 def deserialize_aggregated_activities( 2008 self, payload: typedefs.JSONObject 2009 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 2010 return iterators.FlatIterator( 2011 [ 2012 self.deserialize_aggregated_activity(activity) 2013 for activity in payload["activities"] 2014 ] 2015 )
Deserialize a JSON payload of an array of aggregated activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]: An iterator over aggregated activities objects.
2017 def deserialize_linked_profiles( 2018 self, payload: typedefs.JSONObject 2019 ) -> profile.LinkedProfile: 2020 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 2021 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2022 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2023 2024 if raw_profile := payload.get("profiles"): 2025 for pfile in raw_profile: 2026 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2027 2028 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2029 for raw_error_pfile in raw_profiles_with_errors: 2030 if error_pfile := raw_error_pfile.get("infoCard"): 2031 error_profiles_vec.append( 2032 self.deserialize_destiny_membership(error_pfile) 2033 ) 2034 2035 return profile.LinkedProfile( 2036 net=self._net, 2037 bungie=bungie_user, 2038 profiles=profiles_vec, 2039 profiles_with_errors=error_profiles_vec, 2040 )
Deserialize a JSON payload of Bungie.net hard linked profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.LinkedProfile: A hard linked profile.
2056 def deserialize_public_milestone_content( 2057 self, payload: typedefs.JSONObject 2058 ) -> milestones.MilestoneContent: 2059 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2060 if raw_categories := payload.get("itemCategories"): 2061 for item in raw_categories: 2062 title = undefined.Undefined 2063 if raw_title := item.get("title"): 2064 if raw_title != typedefs.Unknown: 2065 title = raw_title 2066 if raw_hashes := item.get("itemHashes"): 2067 hashes: collections.Sequence[int] = raw_hashes 2068 2069 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2070 2071 about = undefined.Undefined 2072 if (raw_about := payload["about"]) != typedefs.Unknown: 2073 about = raw_about 2074 2075 status = undefined.Undefined 2076 if (raw_status := payload["status"]) != typedefs.Unknown: 2077 status = raw_status 2078 2079 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2080 if raw_tips := payload.get("tips"): 2081 for raw_tip in raw_tips: 2082 if raw_tip == typedefs.Unknown: 2083 raw_tip = undefined.Undefined 2084 tips.append(raw_tip) 2085 2086 return milestones.MilestoneContent( 2087 about=about, status=status, tips=tips, items=items_categoris 2088 )
Deserialize a JSON payload of milestone content information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.MilestoneContent: A milestone content.
2090 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2091 name = undefined.Undefined 2092 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2093 name = raw_name 2094 2095 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2096 2097 if raw_bungie_user := payload.get("bungieNetUser"): 2098 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2099 2100 return friends.Friend( 2101 net=self._net, 2102 id=int(payload["lastSeenAsMembershipId"]), 2103 name=name, 2104 code=payload.get("bungieGlobalDisplayNameCode"), 2105 relationship=enums.Relationship(payload["relationship"]), 2106 user=bungie_user, 2107 online_status=enums.Presence(payload["onlineStatus"]), 2108 online_title=payload["onlineTitle"], 2109 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2110 )
Deserialize a JSON payload of a Bungie friend information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Friend: A friend.
2112 def deserialize_friends( 2113 self, payload: typedefs.JSONObject 2114 ) -> collections.Sequence[friends.Friend]: 2115 mut_seq: typing.MutableSequence[friends.Friend] = [] 2116 if raw_friends := payload.get("friends"): 2117 for friend in raw_friends: 2118 mut_seq.append(self.deserialize_friend(friend)) 2119 return mut_seq
Deserialize a JSON sequence of Bungie friends information.
This is usually used to deserialize the incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of friends.
2121 def deserialize_friend_requests( 2122 self, payload: typedefs.JSONObject 2123 ) -> friends.FriendRequestView: 2124 incoming: typing.MutableSequence[friends.Friend] = [] 2125 outgoing: typing.MutableSequence[friends.Friend] = [] 2126 2127 if raw_incoming_requests := payload.get("incomingRequests"): 2128 for incoming_request in raw_incoming_requests: 2129 incoming.append(self.deserialize_friend(incoming_request)) 2130 2131 if raw_outgoing_requests := payload.get("outgoingRequests"): 2132 for outgoing_request in raw_outgoing_requests: 2133 outgoing.append(self.deserialize_friend(outgoing_request)) 2134 2135 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
Deserialize a JSON sequence of Bungie friend requests information.
This is used for incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.FriendRequestView]: A sequence of incoming and outgoing friends.
2160 def deserialize_fireteams( 2161 self, payload: typedefs.JSONObject 2162 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2163 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2164 2165 result: list[typedefs.JSONObject] 2166 if not (result := payload["results"]): 2167 return None 2168 for elem in result: 2169 fireteams_.append( 2170 self._set_fireteam_fields( 2171 elem, total_results=int(payload["totalResults"]) 2172 ) 2173 ) 2174 return fireteams_
Deserialize a JSON sequence of Bungie fireteams information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Fireteam]: A sequence of fireteam.
2176 def deserialize_fireteam_destiny_users( 2177 self, payload: typedefs.JSONObject 2178 ) -> fireteams.FireteamUser: 2179 destiny_obj = self.deserialize_destiny_membership(payload) 2180 # We could helpers.just return a DestinyMembership object but this is 2181 # missing the fireteam display name and id fields. 2182 return fireteams.FireteamUser( 2183 net=self._net, 2184 id=destiny_obj.id, 2185 code=destiny_obj.code, 2186 icon=destiny_obj.icon, 2187 types=destiny_obj.types, 2188 type=destiny_obj.type, 2189 is_public=destiny_obj.is_public, 2190 crossave_override=destiny_obj.crossave_override, 2191 name=destiny_obj.name, 2192 last_seen_name=destiny_obj.last_seen_name, 2193 fireteam_display_name=payload["FireteamDisplayName"], 2194 fireteam_membership_id=enums.MembershipType( 2195 payload["FireteamMembershipType"] 2196 ), 2197 )
Deserialize a JSON payload of Bungie fireteam destiny users information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamUser: A fireteam user.
2199 def deserialize_fireteam_members( 2200 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2201 ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]: 2202 members_: list[fireteams.FireteamMember] = [] 2203 if members := payload.get("Members" if not alternatives else "Alternates"): 2204 for member in members: 2205 bungie_fields = self.deserialize_partial_bungie_user(member) 2206 members_fields = fireteams.FireteamMember( 2207 destiny_user=self.deserialize_fireteam_destiny_users(member), 2208 has_microphone=member["hasMicrophone"], 2209 character_id=int(member["characterId"]), 2210 date_joined=time.clean_date(member["dateJoined"]), 2211 last_platform_invite_date=time.clean_date( 2212 member["lastPlatformInviteAttemptDate"] 2213 ), 2214 last_platform_invite_result=int( 2215 member["lastPlatformInviteAttemptResult"] 2216 ), 2217 net=self._net, 2218 name=bungie_fields.name, 2219 id=bungie_fields.id, 2220 icon=bungie_fields.icon, 2221 is_public=bungie_fields.is_public, 2222 crossave_override=bungie_fields.crossave_override, 2223 types=bungie_fields.types, 2224 type=bungie_fields.type, 2225 ) 2226 members_.append(members_fields) 2227 else: 2228 return None 2229 return members_
Deserialize a JSON sequence of Bungie fireteam members information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - alternatives (
bool): If set toTrue, Then it will deserialize thealternativesdata in the payload. If not the it will just deserialize themembersdata.
Returns
typing.Optional[collections.Sequence[aiobungie.crates.FireteamUser]]: An optional sequence of the fireteam members.
2231 def deserialize_available_fireteams( 2232 self, 2233 data: typedefs.JSONObject, 2234 *, 2235 no_results: bool = False, 2236 ) -> typing.Union[ 2237 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2238 ]: 2239 fireteams_: list[fireteams.AvailableFireteam] = [] 2240 2241 # This needs to be used outside the results 2242 # JSON key. 2243 if no_results is True: 2244 payload = data 2245 2246 if result := payload.get("results"): 2247 2248 for fireteam in result: 2249 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2250 fireteams_fields = fireteams.AvailableFireteam( 2251 id=found_fireteams.id, 2252 group_id=found_fireteams.group_id, 2253 platform=found_fireteams.platform, 2254 activity_type=found_fireteams.activity_type, 2255 is_immediate=found_fireteams.is_immediate, 2256 is_public=found_fireteams.is_public, 2257 is_valid=found_fireteams.is_valid, 2258 owner_id=found_fireteams.owner_id, 2259 player_slot_count=found_fireteams.player_slot_count, 2260 available_player_slots=found_fireteams.available_player_slots, 2261 available_alternate_slots=found_fireteams.available_alternate_slots, 2262 title=found_fireteams.title, 2263 date_created=found_fireteams.date_created, 2264 locale=found_fireteams.locale, 2265 last_modified=found_fireteams.last_modified, 2266 total_results=found_fireteams.total_results, 2267 members=self.deserialize_fireteam_members(payload), 2268 alternatives=self.deserialize_fireteam_members( 2269 payload, alternatives=True 2270 ), 2271 ) 2272 fireteams_.append(fireteams_fields) 2273 if no_results: 2274 return fireteams_fields 2275 return fireteams_
Deserialize a JSON payload of a sequence of/fireteam information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - no_results (
bool): Whether to deserialize the data fromresultsin the payload or not.
Returns
typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]# noqa (E501): An available fireteam or a sequence of available fireteam.
2277 def deserialize_fireteam_party( 2278 self, payload: typedefs.JSONObject 2279 ) -> fireteams.FireteamParty: 2280 last_destination_hash: typing.Optional[int] = None 2281 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2282 last_destination_hash = int(raw_dest_hash) 2283 2284 return fireteams.FireteamParty( 2285 members=[ 2286 self._deserialize_fireteam_party_member(member) 2287 for member in payload["partyMembers"] 2288 ], 2289 activity=self._deserialize_fireteam_party_current_activity( 2290 payload["currentActivity"] 2291 ), 2292 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2293 last_destination_hash=last_destination_hash, 2294 tracking=payload["tracking"], 2295 )
Deserialize a JSON payload of profileTransitory component response.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamParty: A fireteam party object of the current fireteam.
2342 def deserialize_seasonal_artifact( 2343 self, payload: typedefs.JSONObject 2344 ) -> season.Artifact: 2345 if raw_artifact := payload.get("seasonalArtifact"): 2346 if points := raw_artifact.get("pointProgression"): 2347 points_prog = progressions.Progression( 2348 hash=points["progressionHash"], 2349 level=points["level"], 2350 cap=points["levelCap"], 2351 daily_limit=points["dailyLimit"], 2352 weekly_limit=points["weeklyLimit"], 2353 current_progress=points["currentProgress"], 2354 daily_progress=points["dailyProgress"], 2355 needed=points["progressToNextLevel"], 2356 next_level=points["nextLevelAt"], 2357 ) 2358 2359 if bonus := raw_artifact.get("powerBonusProgression"): 2360 power_bonus_prog = progressions.Progression( 2361 hash=bonus["progressionHash"], 2362 level=bonus["level"], 2363 cap=bonus["levelCap"], 2364 daily_limit=bonus["dailyLimit"], 2365 weekly_limit=bonus["weeklyLimit"], 2366 current_progress=bonus["currentProgress"], 2367 daily_progress=bonus["dailyProgress"], 2368 needed=bonus["progressToNextLevel"], 2369 next_level=bonus["nextLevelAt"], 2370 ) 2371 artifact = season.Artifact( 2372 net=self._net, 2373 hash=raw_artifact["artifactHash"], 2374 power_bonus=raw_artifact["powerBonus"], 2375 acquired_points=raw_artifact["pointsAcquired"], 2376 bonus=power_bonus_prog, 2377 points=points_prog, 2378 ) 2379 return artifact
Deserialize a JSON payload of a Destiny 2 seasonal artifact information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Artifact: A seasonal artifact.
2381 def deserialize_profile_progression( 2382 self, payload: typedefs.JSONObject 2383 ) -> profile.ProfileProgression: 2384 return profile.ProfileProgression( 2385 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2386 checklist={ 2387 int(check_id): checklists 2388 for check_id, checklists in payload["data"]["checklists"].items() 2389 }, 2390 )
Deserialize a JSON payload of a profile progression component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ProfileProgression: A profile progression component.
2392 def deserialize_instanced_item( 2393 self, payload: typedefs.JSONObject 2394 ) -> items.ItemInstance: 2395 damage_type_hash: typing.Optional[int] = None 2396 if raw_damagetype_hash := payload.get("damageTypeHash"): 2397 damage_type_hash = int(raw_damagetype_hash) 2398 2399 required_hashes: typing.Optional[collections.Collection[int]] = None 2400 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2401 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2402 2403 breaker_type: typing.Optional[items.ItemBreakerType] = None 2404 if raw_break_type := payload.get("breakerType"): 2405 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2406 2407 breaker_type_hash: typing.Optional[int] = None 2408 if raw_break_type_hash := payload.get("breakerTypeHash"): 2409 breaker_type_hash = int(raw_break_type_hash) 2410 2411 energy: typing.Optional[items.ItemEnergy] = None 2412 if raw_energy := payload.get("energy"): 2413 energy = self.deserialize_item_energy(raw_energy) 2414 2415 primary_stats = None 2416 if raw_primary_stats := payload.get("primaryStat"): 2417 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2418 2419 return items.ItemInstance( 2420 damage_type=enums.DamageType(int(payload["damageType"])), 2421 damage_type_hash=damage_type_hash, 2422 primary_stat=primary_stats, 2423 item_level=int(payload["itemLevel"]), 2424 quality=int(payload["quality"]), 2425 is_equipped=payload["isEquipped"], 2426 can_equip=payload["canEquip"], 2427 equip_required_level=int(payload["equipRequiredLevel"]), 2428 required_equip_unlock_hashes=required_hashes, 2429 cant_equip_reason=int(payload["cannotEquipReason"]), 2430 breaker_type=breaker_type, 2431 breaker_type_hash=breaker_type_hash, 2432 energy=energy, 2433 )
Deserialize a JSON object into an instanced item.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ItemInstance: An instanced item object.
2435 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2436 energy_hash: typing.Optional[int] = None 2437 if raw_energy_hash := payload.get("energyTypeHash"): 2438 energy_hash = int(raw_energy_hash) 2439 2440 return items.ItemEnergy( 2441 hash=energy_hash, 2442 type=items.ItemEnergyType(int(payload["energyType"])), 2443 capacity=int(payload["energyCapacity"]), 2444 used_energy=int(payload["energyUsed"]), 2445 unused_energy=int(payload["energyUnused"]), 2446 )
2448 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2449 perk_hash: typing.Optional[int] = None 2450 if raw_perk_hash := payload.get("perkHash"): 2451 perk_hash = int(raw_perk_hash) 2452 2453 return items.ItemPerk( 2454 hash=perk_hash, 2455 icon=assets.Image(payload["iconPath"]), 2456 is_active=payload["isActive"], 2457 is_visible=payload["visible"], 2458 )
2460 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2461 plug_hash: typing.Optional[int] = None 2462 if raw_plug_hash := payload.get("plugHash"): 2463 plug_hash = int(raw_plug_hash) 2464 2465 enable_fail_indexes: typing.Optional[list[int]] = None 2466 if raw_indexes := payload.get("enableFailIndexes"): 2467 enable_fail_indexes = [int(index) for index in raw_indexes] 2468 2469 return items.ItemSocket( 2470 plug_hash=plug_hash, 2471 is_enabled=payload["isEnabled"], 2472 enable_fail_indexes=enable_fail_indexes, 2473 is_visible=payload.get("visible"), 2474 )
2483 def deserialize_plug_item_state( 2484 self, payload: typedefs.JSONObject 2485 ) -> items.PlugItemState: 2486 item_hash: typing.Optional[int] = None 2487 if raw_item_hash := payload.get("plugItemHash"): 2488 item_hash = int(raw_item_hash) 2489 2490 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2491 if raw_fail_indexes := payload.get("insertFailIndexes"): 2492 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2493 2494 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2495 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2496 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2497 2498 return items.PlugItemState( 2499 item_hash=item_hash, 2500 insert_fail_indexes=insert_fail_indexes, 2501 enable_fail_indexes=enable_fail_indexes, 2502 is_enabled=payload["enabled"], 2503 can_insert=payload["canInsert"], 2504 )
68@typing.final 69class FireteamActivity(int, enums.Enum): 70 """An enum for the fireteam activities.""" 71 72 ALL = 0 73 CRUCIBLE = 2 74 TRIALS_OF_OSIRIS = 3 75 NIGHTFALL = 4 76 ANY = 5 77 GAMBIT = 6 78 BLIND_WELL = 7 79 NIGHTMARE_HUNTS = 12 80 ALTARS_OF_SORROWS = 14 81 DUNGEON = 15 82 RAID_LW = 20 83 RAID_GOS = 21 84 RAID_DSC = 22 85 EXO_CHALLENGE = 23 86 S12_WRATHBORN = 24 87 EMPIRE_HUNTS = 25 88 S13_BATTLEGROUNDS = 26 89 EXOTIC_QUEST = 27 90 RAID_VOG = 28 91 S14_EXPUNGE = 30 92 S15_ASTRAL_ALIGNMENT = 31 93 S15_SHATTERED_RELAM = 32 94 SHATTERED_THRONE = 33 95 PROPHECY = 34 96 PIT_OF_HERESY = 35 97 DOE = 36 98 """Dares of Eternity.""" 99 DUNGEON_GOA = 37 100 """Grasp of Avarice.""" 101 VOW_OF_THE_DISCPILE = 38 102 CAMPAIGN = 39 103 WELLSPRING = 40 104 S16_BATTLEGROUNDS = 41 105 S17_NIGHTMARE_CONTAINMENT = 44 106 S17_SEVER = 45
An enum for the fireteam activities.
132@typing.final 133class FireteamDate(int, enums.Enum): 134 """An enum for fireteam date ranges.""" 135 136 ALL = 0 137 NOW = 1 138 TODAY = 2 139 TWO_DAYS = 3 140 THIS_WEEK = 4
An enum for fireteam date ranges.
109@typing.final 110class FireteamLanguage(str, enums.Enum): 111 """An enum for fireteams languages filters.""" 112 113 ALL = "" 114 ENGLISH = "en" 115 FRENCH = "fr" 116 ESPANOL = "es" 117 DEUTSCH = "de" 118 ITALIAN = "it" 119 JAPANESE = "ja" 120 PORTUGUESE = "pt-br" 121 RUSSIAN = "ru" 122 POLISH = "pl" 123 KOREAN = "ko" 124 # ? China 125 ZH_CHT = "zh-cht" 126 ZH_CHS = "zh-chs" 127 128 def __str__(self) -> str: 129 return str(self.value)
An enum for fireteams languages filters.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
55@typing.final 56class FireteamPlatform(int, enums.Enum): 57 """An enum for fireteam related to bungie fireteams. 58 This is different from the normal `aiobungie.MembershipType`. 59 """ 60 61 ANY = 0 62 PSN_NETWORK = 1 63 XBOX_LIVE = 2 64 STEAM = 4 65 STADIA = 5
An enum for fireteam related to bungie fireteams.
This is different from the normal aiobungie.MembershipType.
102class Flag(__enum.Flag): 103 """Builtin Python enum flag with extra handlings.""" 104 105 # Needs to type this here for mypy 106 _value_: int 107 108 @property 109 def name(self) -> str: # type: ignore[override] 110 if self._name_ is None: 111 self._name_ = f"UNKNOWN {self._value_}" 112 113 return self._name_ 114 115 @property 116 def value(self) -> int: # type: ignore[override] 117 return self._value_ 118 119 def __str__(self) -> str: 120 return self.name 121 122 def __repr__(self) -> str: 123 return f"<{type(self).__name__}.{self.name}: {self._value_!s}>" 124 125 def __int__(self) -> int: 126 if isinstance(self.value, _ITERABLE): 127 raise TypeError( 128 f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.", 129 ) 130 return int(self.value) 131 132 def __or__(self, other: typing.Union[Flag, int]) -> Flag: 133 return self.__class__(self._value_ | int(other)) 134 135 def __xor__(self, other: typing.Union[Flag, int]) -> Flag: 136 return self.__class__(self._value_ ^ int(other)) 137 138 def __and__(self, other: typing.Union[Flag, int]) -> Flag: 139 return self.__class__(other & int(other)) 140 141 def __invert__(self) -> Flag: 142 return self.__class__(~self._value_) 143 144 def __contains__(self, other: typing.Union[Flag, int]) -> bool: 145 return self.value & int(other) == int(other)
Builtin Python enum flag with extra handlings.
43class FlatIterator(typing.Generic[Item]): 44 """A Flat, In-Memory iterator for sequenced based data. 45 46 This can either be used sync or asynchronously. 47 48 Example 49 ------- 50 ```py 51 iterator = FlatIterator([1, 2, 3]) 52 53 # Limit the results to 2. 54 async for item in iterator.take(2): 55 print(item) 56 # 1 57 # 2 58 59 # Filter the results. 60 async for item in iterator.filter(lambda item: item > 1): 61 print(item) 62 print(iterator.count()) 63 # 2 64 # 3 65 # 3 66 67 # Map the results. 68 async for item in iterator.map(lambda item: item * 2): 69 print(item) 70 # 2 71 # 4 72 73 # This also works synchronously. 74 iterator = FlatIterator(["Hello", "World", "!"]) 75 for item in iterator.discard(lambda item: "!" in item): 76 print(item) 77 # Hello 78 # World 79 80 # Indexing is also supported. 81 82 print(iterator[0]) 83 # Hello 84 ``` 85 86 Parameters 87 ---------- 88 items: `collections.Iterable[Item]` 89 The items to iterate over. 90 """ 91 92 __slots__ = ("_items",) 93 94 def __init__(self, items: collections.Iterable[Item]) -> None: 95 self._items = iter(items) 96 97 @typing.overload 98 def collect(self) -> list[Item]: 99 ... 100 101 @typing.overload 102 def collect(self, casting: _B) -> list[_B]: 103 """Collects all items in the iterator into a list and cast them into an object if provided. 104 105 Example 106 ------- 107 >>> iterator = FlatIterator([1, 2, 3]) 108 >>> iterator.collect(casting=str) 109 ["1", "2", "3"] 110 111 Parameters 112 ---------- 113 casting: `T | None` 114 The type to cast the items to. If `None` is provided, the items will be returned as is. 115 116 Raises 117 ------ 118 `StopIteration` 119 If no elements are left in the iterator. 120 """ 121 ... 122 123 def collect( 124 self, casting: typing.Optional[_B] = None 125 ) -> typing.Union[list[Item], list[_B]]: 126 """Collects all items in the iterator into a list. 127 128 Example 129 ------- 130 >>> iterator = FlatIterator([1, 2, 3]) 131 >>> iterator.collect() 132 [1, 2, 3] 133 134 Raises 135 ------ 136 `StopIteration` 137 If no elements are left in the iterator. 138 """ 139 if casting is not None: 140 return typing.cast(list[_B], list(map(casting, self._items))) 141 142 return list(self._items) 143 144 def next(self) -> Item: 145 """Returns the next item in the iterator. 146 147 Example 148 ------- 149 >>> iterator = FlatIterator[str](["1", "2", "3"]) 150 item = iterator.next() 151 assert item == "1" 152 item = iterator.next() 153 assert item == "2" 154 155 Raises 156 ------ 157 `StopIteration` 158 If no elements are left in the iterator. 159 """ 160 try: 161 return self.__next__() 162 except StopIteration: 163 self._ok() 164 165 def map( 166 self, predicate: collections.Callable[[Item], OtherItem] 167 ) -> FlatIterator[OtherItem]: 168 """Maps each item in the iterator to its predicated value. 169 170 Example 171 ------- 172 >>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value)) 173 <FlatIterator([1, 2, 3])> 174 >>> async for item in iterator: 175 assert isinstance(item, int) 176 177 Parameters 178 ---------- 179 predicate: `collections.Callable[[Item], Item]` 180 The function to map each item in the iterator to its predicated value. 181 182 Raises 183 ------ 184 `StopIteration` 185 If no elements are left in the iterator. 186 """ 187 return FlatIterator(map(predicate, self._items)) 188 189 def take(self, n: int) -> FlatIterator[Item]: 190 """Take the first number of items until the number of items are yielded or 191 the end of the iterator is reached. 192 193 Example 194 ------- 195 >>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 196 >>> async for mode in iterator.take(2): 197 assert mode in [GameMode.RAID, GameMode.STRIKE] 198 <FlatIterator([GameMode.RAID, GameMode.STRIKE])> 199 200 Parameters 201 ---------- 202 n: `int` 203 The number of items to take. 204 205 Raises 206 ------ 207 `StopIteration` 208 If no elements are left in the iterator. 209 """ 210 return FlatIterator(itertools.islice(self._items, n)) 211 212 def take_while( 213 self, predicate: collections.Callable[[Item], bool] 214 ) -> FlatIterator[Item]: 215 """Yields items from the iterator while predicate returns `True`. 216 217 Example 218 ------- 219 ```py 220 iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 221 222 async for platform in ( 223 iterator 224 .take_while(lambda platform: platform is not MembershipType.XBOX) 225 ): 226 print(platform) 227 # <FlatIterator([MembershipType.STEAM])> 228 ``` 229 230 Parameters 231 ---------- 232 predicate: `collections.Callable[[Item], bool]` 233 The function to predicate each item in the iterator. 234 235 Raises 236 ------ 237 `StopIteration` 238 If no elements are left in the iterator. 239 """ 240 return FlatIterator(itertools.takewhile(predicate, self._items)) 241 242 def drop_while( 243 self, predicate: collections.Callable[[Item], bool] 244 ) -> FlatIterator[Item]: 245 """Yields items from the iterator while predicate returns `False`. 246 247 Example 248 ------- 249 ```py 250 iterator = FlatIterator( 251 [DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")] 252 ) 253 254 async for membership in ( 255 iterator 256 .drop_while(lambda membership: membership.name is not "Jim") 257 ): 258 print(membership) 259 # <FlatIterator([DestinyMembership(name="Bob")])> 260 ``` 261 262 Parameters 263 ---------- 264 predicate: `collections.Callable[[Item], bool]` 265 The function to predicate each item in the iterator. 266 267 Raises 268 ------ 269 `StopIteration` 270 If no elements are left in the iterator. 271 """ 272 return FlatIterator(itertools.dropwhile(predicate, self._items)) 273 274 def filter( 275 self, predicate: collections.Callable[[Item], bool] 276 ) -> FlatIterator[Item]: 277 """Filters the iterator to only yield items that match the predicate. 278 279 Example 280 ------- 281 ```py 282 activities = FlatIterator( 283 [Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)] 284 # Assuming Raid is solo, Strike is flawless. 285 ) 286 287 async for activity in ( 288 activities 289 .filter(lambda activity: activity.is_solo or activity.is_flawless) 290 ): 291 print(member) 292 # <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])> 293 ``` 294 """ 295 return FlatIterator(filter(predicate, self._items)) 296 297 def skip(self, n: int) -> FlatIterator[Item]: 298 """Skips the first number of items in the iterator. 299 300 Example 301 ------- 302 ```py 303 iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 304 305 async for platform in iterator.skip(1): 306 print(platform) 307 # Skip the first item in the iterator. 308 # <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])> 309 """ 310 return FlatIterator(itertools.islice(self._items, n, None)) 311 312 def discard( 313 self, predicate: collections.Callable[[Item], bool] 314 ) -> FlatIterator[Item]: 315 """Discards all elements in the iterator for which the predicate function returns true. 316 317 Example 318 ------- 319 >>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 320 >>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM): 321 # Drops all memberships that are not steam. 322 print(iterator) 323 <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])> 324 325 Parameters 326 ---------- 327 predicate: `collections.Callable[[Item], bool]` 328 The function to test each item in the iterator. 329 330 Raises 331 ------ 332 `StopIteration` 333 If no elements are left in the iterator. 334 """ 335 return FlatIterator(filter(lambda x: not predicate(x), self._items)) 336 337 def zip( 338 self, other: FlatIterator[OtherItem] 339 ) -> FlatIterator[tuple[Item, OtherItem]]: 340 """Zips the iterator with another iterable. 341 342 Example 343 ------- 344 >>> iterator = FlatIterator([1, 2, 3]) 345 >>> other = FlatIterator([4, 5, 6]) 346 >>> async for item, other_item in iterator.zip(other): 347 assert item == other_item 348 <FlatIterator([(1, 4), (2, 5), (3, 6)])> 349 350 Parameters 351 ---------- 352 other: `FlatIterator[OtherItem]` 353 The iterable to zip with. 354 355 Raises 356 ------ 357 `StopIteration` 358 If no elements are left in the iterator. 359 """ 360 return FlatIterator(zip(self._items, other)) 361 362 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 363 """`True` if all items in the iterator match the predicate. 364 365 Example 366 ------- 367 >>> iterator = FlatIterator([1, 2, 3]) 368 >>> while iterator.all(lambda item: isinstance(item, int)): 369 print("Still all integers") 370 continue 371 # Still all integers 372 373 Parameters 374 ---------- 375 predicate: `collections.Callable[[Item], bool]` 376 The function to test each item in the iterator. 377 378 Raises 379 ------ 380 `StopIteration` 381 If no elements are left in the iterator. 382 """ 383 return all(predicate(item) for item in self) 384 385 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 386 """`True` if any items in the iterator match the predicate. 387 388 Example 389 ------- 390 >>> iterator = FlatIterator([1, 2, 3]) 391 >>> if iterator.any(lambda item: isinstance(item, int)): 392 print("At least one item is an int.") 393 # At least one item is an int. 394 395 Parameters 396 ---------- 397 predicate: `collections.Callable[[Item], bool]` 398 The function to test each item in the iterator. 399 400 Raises 401 ------ 402 `StopIteration` 403 If no elements are left in the iterator. 404 """ 405 return any(predicate(item) for item in self) 406 407 def sort( 408 self, 409 *, 410 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 411 reverse: bool = False, 412 ) -> FlatIterator[Item]: 413 """Sorts the iterator. 414 415 Example 416 ------- 417 >>> iterator = FlatIterator([3, 1, 6, 7]) 418 >>> async for item in iterator.sort(key=lambda item: item < 3): 419 print(item) 420 # 1 421 # 3 422 # 6 423 # 7 424 425 Parameters 426 ---------- 427 key: `collections.Callable[[Item], Any]` 428 The function to sort by. 429 reverse: `bool` 430 Whether to reverse the sort. 431 432 Raises 433 ------ 434 `StopIteration` 435 If no elements are left in the iterator. 436 """ 437 return FlatIterator(sorted(self._items, key=key, reverse=reverse)) 438 439 def first(self) -> Item: 440 """Returns the first item in the iterator. 441 442 Example 443 ------- 444 >>> iterator = FlatIterator([3, 1, 6, 7]) 445 >>> iterator.first() 446 3 447 448 Raises 449 ------ 450 `StopIteration` 451 If no elements are left in the iterator. 452 """ 453 return self.take(1).next() 454 455 def reversed(self) -> FlatIterator[Item]: 456 """Returns a new iterator that yields the items in the iterator in reverse order. 457 458 Example 459 ------- 460 >>> iterator = FlatIterator([3, 1, 6, 7]) 461 >>> async for item in iterator.reversed(): 462 print(item) 463 # 7 464 # 6 465 # 1 466 # 3 467 468 Raises 469 ------ 470 `StopIteration` 471 If no elements are left in the iterator. 472 """ 473 return FlatIterator(reversed(self.collect())) 474 475 def count(self) -> int: 476 count = 0 477 for _ in self: 478 count += 1 479 480 return count 481 482 def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]: 483 """Returns a new iterator that yields all items from both iterators. 484 485 Example 486 ------- 487 >>> iterator = FlatIterator([1, 2, 3]) 488 >>> other = FlatIterator([4, 5, 6]) 489 >>> async for item in iterator.union(other): 490 print(item) 491 # 1 492 # 2 493 # 3 494 # 4 495 # 5 496 # 6 497 498 Parameters 499 ---------- 500 other: `FlatIterator[Item]` 501 The iterable to union with. 502 503 Raises 504 ------ 505 `StopIteration` 506 If no elements are left in the iterator. 507 """ 508 return FlatIterator(itertools.chain(self._items, other)) 509 510 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 511 """Calls the function on each item in the iterator. 512 513 Example 514 ------- 515 >>> iterator = FlatIterator([1, 2, 3]) 516 >>> iterator.for_each(lambda item: print(item)) 517 # 1 518 # 2 519 # 3 520 521 Parameters 522 ---------- 523 func: `typeshed.Callable[[Item], None]` 524 The function to call on each item in the iterator. 525 """ 526 for item in self: 527 func(item) 528 529 def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]: 530 """Returns a new iterator that yields tuples of the index and item. 531 532 Example 533 ------- 534 >>> iterator = FlatIterator([1, 2, 3]) 535 >>> async for index, item in iterator.enumerate(): 536 print(index, item) 537 538 # 0, 1 539 # 1, 2 540 # 2, 3 541 542 Raises 543 ------ 544 `StopIteration` 545 If no elements are left in the iterator. 546 """ 547 return FlatIterator(enumerate(self._items, start=start)) 548 549 def _ok(self) -> typing.NoReturn: 550 raise StopIteration("No more items in the iterator.") from None 551 552 def __getitem__(self, index: int) -> Item: 553 try: 554 return self.skip(index).first() 555 except IndexError: 556 self._ok() 557 558 # This is a never. 559 def __setitem__(self) -> typing.NoReturn: 560 raise TypeError( 561 f"{type(self).__name__} doesn't support item assignment." 562 ) from None 563 564 def __repr__(self) -> str: 565 return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>' 566 567 def __len__(self) -> int: 568 return self.count() 569 570 # We support both sync and async iter. 571 def __iter__(self) -> FlatIterator[Item]: 572 return self 573 574 def __aiter__(self) -> FlatIterator[Item]: 575 return self 576 577 def __next__(self) -> Item: 578 try: 579 item = next(self._items) 580 except StopIteration: 581 self._ok() 582 583 return item 584 585 async def __anext__(self) -> Item: 586 try: 587 item = next(self._items) 588 except StopIteration as e: 589 raise StopAsyncIteration from e 590 591 return item
A Flat, In-Memory iterator for sequenced based data.
This can either be used sync or asynchronously.
Example
iterator = FlatIterator([1, 2, 3])
# Limit the results to 2.
async for item in iterator.take(2):
print(item)
# 1
# 2
# Filter the results.
async for item in iterator.filter(lambda item: item > 1):
print(item)
print(iterator.count())
# 2
# 3
# 3
# Map the results.
async for item in iterator.map(lambda item: item * 2):
print(item)
# 2
# 4
# This also works synchronously.
iterator = FlatIterator(["Hello", "World", "!"])
for item in iterator.discard(lambda item: "!" in item):
print(item)
# Hello
# World
# Indexing is also supported.
print(iterator[0])
# Hello
Parameters
- items (
collections.Iterable[Item]): The items to iterate over.
123 def collect( 124 self, casting: typing.Optional[_B] = None 125 ) -> typing.Union[list[Item], list[_B]]: 126 """Collects all items in the iterator into a list. 127 128 Example 129 ------- 130 >>> iterator = FlatIterator([1, 2, 3]) 131 >>> iterator.collect() 132 [1, 2, 3] 133 134 Raises 135 ------ 136 `StopIteration` 137 If no elements are left in the iterator. 138 """ 139 if casting is not None: 140 return typing.cast(list[_B], list(map(casting, self._items))) 141 142 return list(self._items)
Collects all items in the iterator into a list.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.collect()
[1, 2, 3]
Raises
StopIteration: If no elements are left in the iterator.
144 def next(self) -> Item: 145 """Returns the next item in the iterator. 146 147 Example 148 ------- 149 >>> iterator = FlatIterator[str](["1", "2", "3"]) 150 item = iterator.next() 151 assert item == "1" 152 item = iterator.next() 153 assert item == "2" 154 155 Raises 156 ------ 157 `StopIteration` 158 If no elements are left in the iterator. 159 """ 160 try: 161 return self.__next__() 162 except StopIteration: 163 self._ok()
Returns the next item in the iterator.
Example
>>> iterator = FlatIterator[str](["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
StopIteration: If no elements are left in the iterator.
165 def map( 166 self, predicate: collections.Callable[[Item], OtherItem] 167 ) -> FlatIterator[OtherItem]: 168 """Maps each item in the iterator to its predicated value. 169 170 Example 171 ------- 172 >>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value)) 173 <FlatIterator([1, 2, 3])> 174 >>> async for item in iterator: 175 assert isinstance(item, int) 176 177 Parameters 178 ---------- 179 predicate: `collections.Callable[[Item], Item]` 180 The function to map each item in the iterator to its predicated value. 181 182 Raises 183 ------ 184 `StopIteration` 185 If no elements are left in the iterator. 186 """ 187 return FlatIterator(map(predicate, self._items))
Maps each item in the iterator to its predicated value.
Example
>>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value))
<FlatIterator([1, 2, 3])>
>>> async for item in iterator:
assert isinstance(item, int)
Parameters
- predicate (
collections.Callable[[Item], Item]): The function to map each item in the iterator to its predicated value.
Raises
StopIteration: If no elements are left in the iterator.
189 def take(self, n: int) -> FlatIterator[Item]: 190 """Take the first number of items until the number of items are yielded or 191 the end of the iterator is reached. 192 193 Example 194 ------- 195 >>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 196 >>> async for mode in iterator.take(2): 197 assert mode in [GameMode.RAID, GameMode.STRIKE] 198 <FlatIterator([GameMode.RAID, GameMode.STRIKE])> 199 200 Parameters 201 ---------- 202 n: `int` 203 The number of items to take. 204 205 Raises 206 ------ 207 `StopIteration` 208 If no elements are left in the iterator. 209 """ 210 return FlatIterator(itertools.islice(self._items, n))
Take the first number of items until the number of items are yielded or the end of the iterator is reached.
Example
>>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
>>> async for mode in iterator.take(2):
assert mode in [GameMode.RAID, GameMode.STRIKE]
<FlatIterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
- n (
int): The number of items to take.
Raises
StopIteration: If no elements are left in the iterator.
212 def take_while( 213 self, predicate: collections.Callable[[Item], bool] 214 ) -> FlatIterator[Item]: 215 """Yields items from the iterator while predicate returns `True`. 216 217 Example 218 ------- 219 ```py 220 iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 221 222 async for platform in ( 223 iterator 224 .take_while(lambda platform: platform is not MembershipType.XBOX) 225 ): 226 print(platform) 227 # <FlatIterator([MembershipType.STEAM])> 228 ``` 229 230 Parameters 231 ---------- 232 predicate: `collections.Callable[[Item], bool]` 233 The function to predicate each item in the iterator. 234 235 Raises 236 ------ 237 `StopIteration` 238 If no elements are left in the iterator. 239 """ 240 return FlatIterator(itertools.takewhile(predicate, self._items))
Yields items from the iterator while predicate returns True.
Example
iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
async for platform in (
iterator
.take_while(lambda platform: platform is not MembershipType.XBOX)
):
print(platform)
# <FlatIterator([MembershipType.STEAM])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
242 def drop_while( 243 self, predicate: collections.Callable[[Item], bool] 244 ) -> FlatIterator[Item]: 245 """Yields items from the iterator while predicate returns `False`. 246 247 Example 248 ------- 249 ```py 250 iterator = FlatIterator( 251 [DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")] 252 ) 253 254 async for membership in ( 255 iterator 256 .drop_while(lambda membership: membership.name is not "Jim") 257 ): 258 print(membership) 259 # <FlatIterator([DestinyMembership(name="Bob")])> 260 ``` 261 262 Parameters 263 ---------- 264 predicate: `collections.Callable[[Item], bool]` 265 The function to predicate each item in the iterator. 266 267 Raises 268 ------ 269 `StopIteration` 270 If no elements are left in the iterator. 271 """ 272 return FlatIterator(itertools.dropwhile(predicate, self._items))
Yields items from the iterator while predicate returns False.
Example
iterator = FlatIterator(
[DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]
)
async for membership in (
iterator
.drop_while(lambda membership: membership.name is not "Jim")
):
print(membership)
# <FlatIterator([DestinyMembership(name="Bob")])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
274 def filter( 275 self, predicate: collections.Callable[[Item], bool] 276 ) -> FlatIterator[Item]: 277 """Filters the iterator to only yield items that match the predicate. 278 279 Example 280 ------- 281 ```py 282 activities = FlatIterator( 283 [Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)] 284 # Assuming Raid is solo, Strike is flawless. 285 ) 286 287 async for activity in ( 288 activities 289 .filter(lambda activity: activity.is_solo or activity.is_flawless) 290 ): 291 print(member) 292 # <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])> 293 ``` 294 """ 295 return FlatIterator(filter(predicate, self._items))
Filters the iterator to only yield items that match the predicate.
Example
activities = FlatIterator(
[Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)]
# Assuming Raid is solo, Strike is flawless.
)
async for activity in (
activities
.filter(lambda activity: activity.is_solo or activity.is_flawless)
):
print(member)
# <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])>
297 def skip(self, n: int) -> FlatIterator[Item]: 298 """Skips the first number of items in the iterator. 299 300 Example 301 ------- 302 ```py 303 iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 304 305 async for platform in iterator.skip(1): 306 print(platform) 307 # Skip the first item in the iterator. 308 # <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])> 309 """ 310 return FlatIterator(itertools.islice(self._items, n, None))
Skips the first number of items in the iterator.
Example
```py iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
async for platform in iterator.skip(1): print(platform)
Skip the first item in the iterator.
MembershipType.XBOX, MembershipType.STADIA])>
312 def discard( 313 self, predicate: collections.Callable[[Item], bool] 314 ) -> FlatIterator[Item]: 315 """Discards all elements in the iterator for which the predicate function returns true. 316 317 Example 318 ------- 319 >>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 320 >>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM): 321 # Drops all memberships that are not steam. 322 print(iterator) 323 <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])> 324 325 Parameters 326 ---------- 327 predicate: `collections.Callable[[Item], bool]` 328 The function to test each item in the iterator. 329 330 Raises 331 ------ 332 `StopIteration` 333 If no elements are left in the iterator. 334 """ 335 return FlatIterator(filter(lambda x: not predicate(x), self._items))
Discards all elements in the iterator for which the predicate function returns true.
Example
>>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
>>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM):
# Drops all memberships that are not steam.
print(iterator)
<FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
337 def zip( 338 self, other: FlatIterator[OtherItem] 339 ) -> FlatIterator[tuple[Item, OtherItem]]: 340 """Zips the iterator with another iterable. 341 342 Example 343 ------- 344 >>> iterator = FlatIterator([1, 2, 3]) 345 >>> other = FlatIterator([4, 5, 6]) 346 >>> async for item, other_item in iterator.zip(other): 347 assert item == other_item 348 <FlatIterator([(1, 4), (2, 5), (3, 6)])> 349 350 Parameters 351 ---------- 352 other: `FlatIterator[OtherItem]` 353 The iterable to zip with. 354 355 Raises 356 ------ 357 `StopIteration` 358 If no elements are left in the iterator. 359 """ 360 return FlatIterator(zip(self._items, other))
Zips the iterator with another iterable.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> other = FlatIterator([4, 5, 6])
>>> async for item, other_item in iterator.zip(other):
assert item == other_item
<FlatIterator([(1, 4), (2, 5), (3, 6)])>
Parameters
- other (
FlatIterator[OtherItem]): The iterable to zip with.
Raises
StopIteration: If no elements are left in the iterator.
362 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 363 """`True` if all items in the iterator match the predicate. 364 365 Example 366 ------- 367 >>> iterator = FlatIterator([1, 2, 3]) 368 >>> while iterator.all(lambda item: isinstance(item, int)): 369 print("Still all integers") 370 continue 371 # Still all integers 372 373 Parameters 374 ---------- 375 predicate: `collections.Callable[[Item], bool]` 376 The function to test each item in the iterator. 377 378 Raises 379 ------ 380 `StopIteration` 381 If no elements are left in the iterator. 382 """ 383 return all(predicate(item) for item in self)
True if all items in the iterator match the predicate.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> while iterator.all(lambda item: isinstance(item, int)):
print("Still all integers")
continue
# Still all integers
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
385 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 386 """`True` if any items in the iterator match the predicate. 387 388 Example 389 ------- 390 >>> iterator = FlatIterator([1, 2, 3]) 391 >>> if iterator.any(lambda item: isinstance(item, int)): 392 print("At least one item is an int.") 393 # At least one item is an int. 394 395 Parameters 396 ---------- 397 predicate: `collections.Callable[[Item], bool]` 398 The function to test each item in the iterator. 399 400 Raises 401 ------ 402 `StopIteration` 403 If no elements are left in the iterator. 404 """ 405 return any(predicate(item) for item in self)
True if any items in the iterator match the predicate.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> if iterator.any(lambda item: isinstance(item, int)):
print("At least one item is an int.")
<h1 id="at-least-one-item-is-an-int">At least one item is an int.</h1>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
407 def sort( 408 self, 409 *, 410 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 411 reverse: bool = False, 412 ) -> FlatIterator[Item]: 413 """Sorts the iterator. 414 415 Example 416 ------- 417 >>> iterator = FlatIterator([3, 1, 6, 7]) 418 >>> async for item in iterator.sort(key=lambda item: item < 3): 419 print(item) 420 # 1 421 # 3 422 # 6 423 # 7 424 425 Parameters 426 ---------- 427 key: `collections.Callable[[Item], Any]` 428 The function to sort by. 429 reverse: `bool` 430 Whether to reverse the sort. 431 432 Raises 433 ------ 434 `StopIteration` 435 If no elements are left in the iterator. 436 """ 437 return FlatIterator(sorted(self._items, key=key, reverse=reverse))
Sorts the iterator.
Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> async for item in iterator.sort(key=lambda item: item < 3):
print(item)
<h1 id="1">1</h1>
3
6
7
Parameters
- key (
collections.Callable[[Item], Any]): The function to sort by. - reverse (
bool): Whether to reverse the sort.
Raises
StopIteration: If no elements are left in the iterator.
439 def first(self) -> Item: 440 """Returns the first item in the iterator. 441 442 Example 443 ------- 444 >>> iterator = FlatIterator([3, 1, 6, 7]) 445 >>> iterator.first() 446 3 447 448 Raises 449 ------ 450 `StopIteration` 451 If no elements are left in the iterator. 452 """ 453 return self.take(1).next()
Returns the first item in the iterator.
Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> iterator.first()
3
Raises
StopIteration: If no elements are left in the iterator.
455 def reversed(self) -> FlatIterator[Item]: 456 """Returns a new iterator that yields the items in the iterator in reverse order. 457 458 Example 459 ------- 460 >>> iterator = FlatIterator([3, 1, 6, 7]) 461 >>> async for item in iterator.reversed(): 462 print(item) 463 # 7 464 # 6 465 # 1 466 # 3 467 468 Raises 469 ------ 470 `StopIteration` 471 If no elements are left in the iterator. 472 """ 473 return FlatIterator(reversed(self.collect()))
Returns a new iterator that yields the items in the iterator in reverse order.
Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> async for item in iterator.reversed():
print(item)
<h1 id="7">7</h1>
6
1
3
Raises
StopIteration: If no elements are left in the iterator.
482 def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]: 483 """Returns a new iterator that yields all items from both iterators. 484 485 Example 486 ------- 487 >>> iterator = FlatIterator([1, 2, 3]) 488 >>> other = FlatIterator([4, 5, 6]) 489 >>> async for item in iterator.union(other): 490 print(item) 491 # 1 492 # 2 493 # 3 494 # 4 495 # 5 496 # 6 497 498 Parameters 499 ---------- 500 other: `FlatIterator[Item]` 501 The iterable to union with. 502 503 Raises 504 ------ 505 `StopIteration` 506 If no elements are left in the iterator. 507 """ 508 return FlatIterator(itertools.chain(self._items, other))
Returns a new iterator that yields all items from both iterators.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> other = FlatIterator([4, 5, 6])
>>> async for item in iterator.union(other):
print(item)
<h1 id="1">1</h1>
2
3
4
5
6
Parameters
- other (
FlatIterator[Item]): The iterable to union with.
Raises
StopIteration: If no elements are left in the iterator.
510 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 511 """Calls the function on each item in the iterator. 512 513 Example 514 ------- 515 >>> iterator = FlatIterator([1, 2, 3]) 516 >>> iterator.for_each(lambda item: print(item)) 517 # 1 518 # 2 519 # 3 520 521 Parameters 522 ---------- 523 func: `typeshed.Callable[[Item], None]` 524 The function to call on each item in the iterator. 525 """ 526 for item in self: 527 func(item)
Calls the function on each item in the iterator.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.for_each(lambda item: print(item))
<h1 id="1">1</h1>
2
3
Parameters
- func (
typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
529 def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]: 530 """Returns a new iterator that yields tuples of the index and item. 531 532 Example 533 ------- 534 >>> iterator = FlatIterator([1, 2, 3]) 535 >>> async for index, item in iterator.enumerate(): 536 print(index, item) 537 538 # 0, 1 539 # 1, 2 540 # 2, 3 541 542 Raises 543 ------ 544 `StopIteration` 545 If no elements are left in the iterator. 546 """ 547 return FlatIterator(enumerate(self._items, start=start))
Returns a new iterator that yields tuples of the index and item.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> async for index, item in iterator.enumerate():
print(index, item)
0, 1
1, 2
2, 3
Raises
StopIteration: If no elements are left in the iterator.
133@attrs.define(auto_exc=True) 134class Forbidden(HTTPException): 135 """Exception that's raised for when status code 403 occurs.""" 136 137 http_status: http.HTTPStatus = attrs.field( 138 default=http.HTTPStatus.FORBIDDEN, init=False 139 )
Exception that's raised for when status code 403 occurs.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class Forbidden.
Inherited Members
- builtins.BaseException
- with_traceback
- args
274@typing.final 275class GameMode(int, Enum): 276 """An Enum for all available gamemodes in Destiny 2.""" 277 278 NONE = 0 279 STORY = 2 280 STRIKE = 3 281 RAID = 4 282 ALLPVP = 5 283 PATROL = 6 284 ALLPVE = 7 285 RESERVED9 = 9 286 CONTROL = 10 287 RESERVED11 = 11 288 CLASH = 12 289 RESERVED13 = 13 290 CRIMSONDOUBLES = 15 291 NIGHTFALL = 16 292 HEROICNIGHTFALL = 17 293 ALLSTRIKES = 18 294 IRONBANNER = 19 295 RESERVED20 = 20 296 RESERVED21 = 21 297 RESERVED22 = 22 298 RESERVED24 = 24 299 ALLMAYHEM = 25 300 RESERVED26 = 26 301 RESERVED27 = 27 302 RESERVED28 = 28 303 RESERVED29 = 29 304 RESERVED30 = 30 305 SUPREMACY = 31 306 PRIVATEMATCHESALL = 32 307 SURVIVAL = 37 308 COUNTDOWN = 38 309 TRIALSOFTHENINE = 39 310 SOCIAL = 40 311 TRIALSCOUNTDOWN = 41 312 TRIALSSURVIVAL = 42 313 IRONBANNERCONTROL = 43 314 IRONBANNERCLASH = 44 315 IRONBANNERSUPREMACY = 45 316 SCOREDNIGHTFALL = 46 317 SCOREDHEROICNIGHTFALL = 47 318 RUMBLE = 48 319 ALLDOUBLES = 49 320 DOUBLES = 50 321 PRIVATEMATCHESCLASH = 51 322 PRIVATEMATCHESCONTROL = 52 323 PRIVATEMATCHESSUPREMACY = 53 324 PRIVATEMATCHESCOUNTDOWN = 54 325 PRIVATEMATCHESSURVIVAL = 55 326 PRIVATEMATCHESMAYHEM = 56 327 PRIVATEMATCHESRUMBLE = 57 328 HEROICADVENTURE = 58 329 SHOWDOWN = 59 330 LOCKDOWN = 60 331 SCORCHED = 61 332 SCORCHEDTEAM = 62 333 GAMBIT = 63 334 ALLPVECOMPETITIVE = 64 335 BREAKTHROUGH = 65 336 BLACKARMORYRUN = 66 337 SALVAGE = 67 338 IRONBANNERSALVAGE = 68 339 PVPCOMPETITIVE = 69 340 PVPQUICKPLAY = 70 341 CLASHQUICKPLAY = 71 342 CLASHCOMPETITIVE = 72 343 CONTROLQUICKPLAY = 73 344 CONTROLCOMPETITIVE = 74 345 GAMBITPRIME = 75 346 RECKONING = 76 347 MENAGERIE = 77 348 VEXOFFENSIVE = 78 349 NIGHTMAREHUNT = 79 350 ELIMINATION = 80 351 MOMENTUM = 81 352 DUNGEON = 82 353 SUNDIAL = 83 354 TRIALS_OF_OSIRIS = 84 355 DARES = 85 356 OFFENSIVE = 86 357 LOSTSECTOR = 87 358 RIFT = 88 359 ZONECONTROL = 89 360 IRONBANNERRIFT = 90
An Enum for all available gamemodes in Destiny 2.
58@typing.final 59class GatingScope(int, enums.Enum): 60 """An enum represents restrictive type of gating that is being performed by an entity. 61 62 This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity 63 applies to everyone equally, or to their specific Profile or Character states. 64 """ 65 66 NONE = 0 67 GLOBAL = 1 68 CLAN = 2 69 PROFILE = 3 70 CHARACTER = 4 71 ITEM = 5 72 ASSUMED_WORST_CASE = 6
An enum represents restrictive type of gating that is being performed by an entity.
This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.
487@typing.final 488class Gender(int, Enum): 489 """An Enum for Destiny Genders.""" 490 491 MALE = 0 492 FEMALE = 1 493 UNKNOWN = 2
An Enum for Destiny Genders.
656@typing.final 657class GroupType(int, Enum): 658 """An enums for the known bungie group types.""" 659 660 GENERAL = 0 661 CLAN = 1
An enums for the known bungie group types.
65@attrs.define(auto_exc=True) 66class HTTPError(AiobungieError): 67 """Exception base used for HTTP request errors.""" 68 69 message: str 70 """The error message.""" 71 72 http_status: http.HTTPStatus 73 """The response status."""
Exception base used for HTTP request errors.
2def __init__(self, message, http_status): 3 self.message = message 4 self.http_status = http_status 5 BaseException.__init__(self, self.message,self.http_status)
Method generated by attrs for class HTTPError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
86@attrs.define(auto_exc=True, kw_only=True) 87class HTTPException(HTTPError): 88 """Exception base internally used for an HTTP request response errors.""" 89 90 error_code: int 91 """The returned Bungie error status code.""" 92 93 http_status: http.HTTPStatus 94 """The request response http status.""" 95 96 throttle_seconds: int 97 """The Bungie response throttle seconds.""" 98 99 url: typing.Optional[typedefs.StrOrURL] 100 """The URL/endpoint caused this error.""" 101 102 body: typing.Any 103 """The response body.""" 104 105 headers: multidict.CIMultiDictProxy[str] 106 """The response headers.""" 107 108 message: str 109 """A Bungie human readable message describes the cause of the error.""" 110 111 error_status: str 112 """A Bungie short error status describes the cause of the error.""" 113 114 message_data: dict[str, str] 115 """A dict of string key, value that includes each cause of the error 116 to a message describes information about that error. 117 """ 118 119 def __str__(self) -> str: 120 if self.message: 121 message_body = self.message 122 123 if self.error_status: 124 error_status_body = self.error_status 125 126 return ( 127 f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: " 128 f"Error status: {error_status_body}, Error message: {message_body} from {self.url} " 129 f"{str(self.body)}" 130 )
Exception base internally used for an HTTP request response errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class HTTPException.
A dict of string key, value that includes each cause of the error to a message describes information about that error.
Inherited Members
- builtins.BaseException
- with_traceback
- args
72class Image: 73 """Representation of an image/avatar/picture at Bungie. 74 75 Example 76 ------- 77 ```py 78 from aiobungie import Image 79 img = Image("img/destiny_content/pgcr/raid_eclipse.jpg") 80 print(img) 81 # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg 82 83 # Stream the image. 84 async for chunk in img: 85 # Byte chunks of the image. 86 print(chunk) 87 88 # Save the image to a file. 89 await img.save("file_name", "/my/path/to/save/to", "jpeg") 90 ``` 91 92 Parameters 93 ---------- 94 path : `str | None` 95 The path to the image. If `None`, the default missing image path will be used. 96 """ 97 98 __slots__ = ("_path",) 99 100 def __init__(self, path: typing.Optional[str] = None) -> None: 101 self._path = path 102 103 @property 104 def is_missing(self) -> bool: 105 return not self._path 106 107 @property 108 def url(self) -> str: 109 """The URL to the image.""" 110 return self.create_url() 111 112 @staticmethod 113 def missing_path() -> str: 114 """Returns the path to the missing Bungie image.""" 115 return "img/misc/missing_icon_d2.png" 116 117 def create_url(self) -> str: 118 """Creates a full URL to the image path. 119 120 Returns 121 ------- 122 str 123 The URL to the image. 124 """ 125 return f"{url.BASE}/{self._path if self._path else self.missing_path()}" 126 127 async def save( 128 self, 129 file_name: str, 130 path: typing.Union[pathlib.Path, str], 131 /, 132 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 133 ) -> None: 134 """Saves the image to a file. 135 136 Parameters 137 ---------- 138 file_name : `str` 139 A name for the file to save the image to. 140 path : `pathlib.Path | str` 141 A path tp save the image to. 142 143 Other Parameters 144 ---------------- 145 mime_type : `MimeType | str` 146 Optional MIME type of the image. 147 148 Raises 149 ------ 150 `FileNotFoundError` 151 If the path provided does not exist. 152 `RuntimeError` 153 If the image could not be saved. 154 `PermissionError` 155 If the path provided is not writable or does not have write permissions. 156 """ 157 if isinstance(path, pathlib.Path) and not path.exists(): 158 raise FileNotFoundError(f"File does not exist: {path!r}") 159 160 if self.is_missing: 161 return 162 163 mimetype = mime_type or MimeType.PNG 164 path = pathlib.Path(path) 165 166 loop = helpers.get_or_make_loop() 167 pool = concurrent.futures.ThreadPoolExecutor() 168 169 try: 170 with pool: 171 await loop.run_in_executor( 172 pool, _write, path, file_name, mimetype, await self.read() 173 ) 174 _LOGGER.info("Saved image to %s", file_name) 175 176 except asyncio.CancelledError: 177 pass 178 179 except Exception as err: 180 raise RuntimeError("Encountered an error while saving image.") from err 181 182 async def read(self) -> bytes: 183 """Read this image bytes. 184 185 Returns 186 ------- 187 `bytes` 188 The bytes of this image. 189 """ 190 client_session = aiohttp.ClientSession() 191 192 try: 193 await client_session.__aenter__() 194 response = await client_session.get(self.create_url()) 195 196 if 300 >= response.status >= 200: 197 reader = await response.read() 198 199 except Exception as exc: 200 raise RuntimeError(f"Failed to read image: {exc}") from None 201 finally: 202 await client_session.__aexit__(None, None, None) 203 return reader 204 205 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 206 """Iterates over the image bytes lazily. 207 208 Example 209 ------- 210 import aiobungie 211 212 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 213 async for chunk in resource.iter(): 214 print(chunk) 215 216 Returns 217 ------- 218 `collections.AsyncGenerator[bytes, None]` 219 An async generator of the image bytes. 220 """ 221 222 async for chunk in self: 223 yield chunk 224 225 def __repr__(self) -> str: 226 return f"Image(url={self.create_url()})" 227 228 def __str__(self) -> str: 229 return self.create_url() 230 231 def __aiter__(self) -> Image: 232 return self 233 234 async def __anext__(self) -> bytes: 235 return await self.read() 236 237 def __await__(self) -> collections.Generator[None, None, bytes]: 238 return self.__anext__().__await__()
Representation of an image/avatar/picture at Bungie.
Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
# Stream the image.
async for chunk in img:
# Byte chunks of the image.
print(chunk)
# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
- path (
str | None): The path to the image. IfNone, the default missing image path will be used.
112 @staticmethod 113 def missing_path() -> str: 114 """Returns the path to the missing Bungie image.""" 115 return "img/misc/missing_icon_d2.png"
Returns the path to the missing Bungie image.
117 def create_url(self) -> str: 118 """Creates a full URL to the image path. 119 120 Returns 121 ------- 122 str 123 The URL to the image. 124 """ 125 return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
Creates a full URL to the image path.
Returns
- str: The URL to the image.
127 async def save( 128 self, 129 file_name: str, 130 path: typing.Union[pathlib.Path, str], 131 /, 132 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 133 ) -> None: 134 """Saves the image to a file. 135 136 Parameters 137 ---------- 138 file_name : `str` 139 A name for the file to save the image to. 140 path : `pathlib.Path | str` 141 A path tp save the image to. 142 143 Other Parameters 144 ---------------- 145 mime_type : `MimeType | str` 146 Optional MIME type of the image. 147 148 Raises 149 ------ 150 `FileNotFoundError` 151 If the path provided does not exist. 152 `RuntimeError` 153 If the image could not be saved. 154 `PermissionError` 155 If the path provided is not writable or does not have write permissions. 156 """ 157 if isinstance(path, pathlib.Path) and not path.exists(): 158 raise FileNotFoundError(f"File does not exist: {path!r}") 159 160 if self.is_missing: 161 return 162 163 mimetype = mime_type or MimeType.PNG 164 path = pathlib.Path(path) 165 166 loop = helpers.get_or_make_loop() 167 pool = concurrent.futures.ThreadPoolExecutor() 168 169 try: 170 with pool: 171 await loop.run_in_executor( 172 pool, _write, path, file_name, mimetype, await self.read() 173 ) 174 _LOGGER.info("Saved image to %s", file_name) 175 176 except asyncio.CancelledError: 177 pass 178 179 except Exception as err: 180 raise RuntimeError("Encountered an error while saving image.") from err
Saves the image to a file.
Parameters
- file_name (
str): A name for the file to save the image to. - path (
pathlib.Path | str): A path tp save the image to.
Other Parameters
- mime_type (
MimeType | str): Optional MIME type of the image.
Raises
FileNotFoundError: If the path provided does not exist.RuntimeError: If the image could not be saved.PermissionError: If the path provided is not writable or does not have write permissions.
182 async def read(self) -> bytes: 183 """Read this image bytes. 184 185 Returns 186 ------- 187 `bytes` 188 The bytes of this image. 189 """ 190 client_session = aiohttp.ClientSession() 191 192 try: 193 await client_session.__aenter__() 194 response = await client_session.get(self.create_url()) 195 196 if 300 >= response.status >= 200: 197 reader = await response.read() 198 199 except Exception as exc: 200 raise RuntimeError(f"Failed to read image: {exc}") from None 201 finally: 202 await client_session.__aexit__(None, None, None) 203 return reader
Read this image bytes.
Returns
bytes: The bytes of this image.
205 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 206 """Iterates over the image bytes lazily. 207 208 Example 209 ------- 210 import aiobungie 211 212 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 213 async for chunk in resource.iter(): 214 print(chunk) 215 216 Returns 217 ------- 218 `collections.AsyncGenerator[bytes, None]` 219 An async generator of the image bytes. 220 """ 221 222 async for chunk in self: 223 yield chunk
Iterates over the image bytes lazily.
Example
import aiobungie
resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)
Returns
collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
203@attrs.define(auto_exc=True) 204class InternalServerError(HTTPException): 205 """Raised for 5xx internal server errors."""
Raised for 5xx internal server errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class InternalServerError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
722@typing.final 723class ItemBindStatus(int, Enum): 724 """An enum for Destiny 2 items bind status.""" 725 726 NOT_BOUND = 0 727 BOUND_TO_CHARACTER = 1 728 BOUND_TO_ACCOUNT = 2 729 BOUNT_TO_GUILD = 3
An enum for Destiny 2 items bind status.
732@typing.final 733class ItemLocation(int, Enum): 734 """An enum for Destiny 2 items location.""" 735 736 UNKNOWN = 0 737 INVENTORY = 1 738 VAULT = 2 739 VENDOR = 3 740 POSTMASTER = 4
An enum for Destiny 2 items location.
757@typing.final 758class ItemState(Flag): 759 """An enum for Destiny 2 item states.""" 760 761 NONE = 0 762 LOCKED = 1 763 TRACKED = 2 764 MASTERWORKED = 4 765 CRAFTED = 8 766 """If this bit is set, the item has been 'crafted' by the player.""" 767 HIGHLITED_OBJECTIVE = 16 768 """If this bit is set, the item is a 'highlighted' objective."""
An enum for Destiny 2 item states.
If this bit is set, the item is a 'highlighted' objective.
589@typing.final 590class ItemSubType(int, Enum): 591 """An enum for Destiny 2 inventory items subtype.""" 592 593 NONE = 0 594 AUTORIFLE = 6 595 SHOTGUN = 7 596 MACHINEGUN = 8 597 HANDCANNON = 9 598 ROCKETLAUNCHER = 10 599 FUSIONRIFLE = 11 600 SNIPERRIFLE = 12 601 PULSERIFLE = 13 602 SCOUTRIFLE = 14 603 SIDEARM = 17 604 SWORD = 18 605 MASK = 19 606 SHADER = 20 607 ORNAMENT = 21 608 FUSIONRIFLELINE = 22 609 GRENADELAUNCHER = 23 610 SUBMACHINEGUN = 24 611 TRACERIFLE = 25 612 HELMETARMOR = 26 613 GAUNTLETSARMOR = 27 614 CHESTARMOR = 28 615 LEGARMOR = 29 616 CLASSARMOR = 30 617 BOW = 31 618 DUMMYREPEATABLEBOUNTY = 32
An enum for Destiny 2 inventory items subtype.
621@typing.final 622class ItemTier(int, Enum): 623 """An enum for a Destiny 2 item tier.""" 624 625 NONE = 0 626 BASIC = 3340296461 627 COMMON = 2395677314 628 RARE = 2127292149 629 LEGENDERY = 4008398120 630 EXOTIC = 2759499571
An enum for a Destiny 2 item tier.
556@typing.final 557class ItemType(int, Enum): 558 """Enums for Destiny2's item types.""" 559 560 NONE = 0 561 CURRENCY = 1 562 ARMOR = 2 563 WEAPON = 3 564 MESSAGE = 7 565 ENGRAM = 8 566 CONSUMABLE = 9 567 EXCHANGEMATERIAL = 10 568 MISSIONREWARD = 11 569 QUESTSTEP = 12 570 QUESTSTEPCOMPLETE = 13 571 EMBLEM = 14 572 QUEST = 15 573 SUBCLASS = 16 574 CLANBANNER = 17 575 AURA = 18 576 MOD = 19 577 DUMMY = 20 578 SHIP = 21 579 VEHICLE = 22 580 EMOTE = 23 581 GHOST = 24 582 PACKAGE = 25 583 BOUNTY = 26 584 WRAPPER = 27 585 SEASONALARTIFACT = 28 586 FINISHER = 29
Enums for Destiny2's item types.
713@typing.final 714class MembershipOption(int, Enum): 715 """A enum for GroupV2 membership options.""" 716 717 REVIEWD = 0 718 OPEN = 1 719 CLOSED = 2
A enum for GroupV2 membership options.
463@typing.final 464class MembershipType(int, Enum): 465 """An Enum for Bungie membership types.""" 466 467 NONE = 0 468 XBOX = 1 469 PSN = 2 470 STEAM = 3 471 BLIZZARD = 4 472 STADIA = 5 473 BUNGIE = 254 474 ALL = -1
An Enum for Bungie membership types.
176@attrs.define(auto_exc=True) 177class MembershipTypeError(BadRequest): 178 """A bad request error raised when passing wrong membership to the request. 179 180 Those fields are useful since it returns the correct membership and id which can be used 181 to make the request again with those fields. 182 """ 183 184 membership_type: str = attrs.field(default="") 185 """The errored membership type passed to the request.""" 186 187 membership_id: int = attrs.field(default=0) 188 """The errored user's membership id.""" 189 190 required_membership: str = attrs.field(default="") 191 """The required correct membership for errored user.""" 192 193 def __str__(self) -> str: 194 return ( 195 f"Expected membership: {self.required_membership}, " 196 f"But got {self.membership_type} for id {self.membership_id}" 197 ) 198 199 def __int__(self) -> int: 200 return int(self.membership_id)
A bad request error raised when passing wrong membership to the request.
Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default, membership_type=attr_dict['membership_type'].default, membership_id=attr_dict['membership_id'].default, required_membership=attr_dict['required_membership'].default): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = http_status 8 self.membership_type = membership_type 9 self.membership_id = membership_id 10 self.required_membership = required_membership 11 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status,self.membership_type,self.membership_id,self.required_membership)
Method generated by attrs for class MembershipTypeError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
506@typing.final 507class MilestoneType(int, Enum): 508 """An Enum for Destiny 2 milestone types.""" 509 510 UNKNOWN = 0 511 TUTORIAL = 1 512 ONETIME = 2 513 WEEKLY = 3 514 DAILY = 4 515 SPECIAL = 5
An Enum for Destiny 2 milestone types.
142@attrs.define(auto_exc=True) 143class NotFound(HTTPException): 144 """Raised when an unknown request was not found.""" 145 146 http_status: http.HTTPStatus = attrs.field( 147 default=http.HTTPStatus.NOT_FOUND, init=False 148 )
Raised when an unknown request was not found.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class NotFound.
Inherited Members
- builtins.BaseException
- with_traceback
- args
94@typing.final 95class ObjectiveUIStyle(int, enums.Enum): 96 NONE = 0 97 HIGHLIGHTED = 1 98 CRAFTING_WEAPON_LEVEL = 2 99 CRAFTING_WEAPON_LEVEL_PROGRESS = 3 100 CRAFTING_WEAPON_TIMESTAMP = 4 101 CRAFTING_MEMENTOS = 5 102 CRAFTING_MEMENTO_TITLE = 6
An enumeration.
235@typing.final 236class Place(int, Enum): 237 """An Enum for Destiny 2 Places and NOT Planets""" 238 239 ORBIT = 2961497387 240 SOCIAL = 4151112093 241 LIGHT_HOUSE = 4276116472 242 EXPLORE = 3497767639
An Enum for Destiny 2 Places and NOT Planets
200@typing.final 201class Planet(int, Enum): 202 """An Enum for all available planets in Destiny 2.""" 203 204 UNKNOWN = 0 205 """Unknown space""" 206 207 EARTH = 3747705955 208 """Earth""" 209 210 DREAMING_CITY = 2877881518 211 """The Dreaming city.""" 212 213 NESSUS = 3526908984 214 """Nessus""" 215 216 MOON = 3325508439 217 """The Moon""" 218 219 COSMODROME = 3990611421 220 """The Cosmodrome""" 221 222 TANGLED_SHORE = 3821439926 223 """The Tangled Shore""" 224 225 VENUS = 3871070152 226 """Venus""" 227 228 EAZ = 541863059 # Exclusive event. 229 """European Aerial Zone""" 230 231 EUROPA = 1729879943 232 """Europa"""
An Enum for all available planets in Destiny 2.
683@typing.final 684class Presence(int, Enum): 685 """An enum for a bungie friend status.""" 686 687 OFFLINE_OR_UNKNOWN = 0 688 ONLINE = 1
An enum for a bungie friend status.
771@typing.final 772class PrivacySetting(int, Enum): 773 """An enum for players's privacy settings.""" 774 775 OPEN = 0 776 CLAN_AND_FRIENDS = 1 777 FRIENDS_ONLY = 2 778 INVITE_ONLY = 3 779 CLOSED = 4
An enum for players's privacy settings.
350class RESTClient(interfaces.RESTInterface): 351 """A RESTful client implementation for Bungie's API. 352 353 This client is designed to only make HTTP requests and return JSON objects 354 to provide RESTful functionality. 355 356 This client is also used within `aiobungie.Client` which deserialize those returned JSON objects 357 using the factory into Pythonic data classes objects which provide Python functionality. 358 359 Example 360 ------- 361 ```py 362 import aiobungie 363 364 async def main(): 365 async with aiobungie.RESTClient("TOKEN") as rest_client: 366 req = await rest_client.fetch_clan_members(4389205) 367 clan_members = req['results'] 368 for member in clan_members: 369 for k, v in member['destinyUserInfo'].items(): 370 print(k, v) 371 ``` 372 373 Parameters 374 ---------- 375 token : `str` 376 A valid application token from Bungie's developer portal. 377 378 Other Parameters 379 ---------------- 380 max_retries : `int` 381 The max retries number to retry if the request hit a `5xx` status code. 382 max_ratelimit_retries : `int` 383 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 384 client_secret : `typing.Optional[str]` 385 An optional application client secret, 386 This is only needed if you're fetching OAuth2 tokens with this client. 387 client_id : `typing.Optional[int]` 388 An optional application client id, 389 This is only needed if you're fetching OAuth2 tokens with this client. 390 enable_debugging : `bool | str` 391 Whether to enable logging responses or not. 392 393 Logging Levels 394 -------------- 395 * `False`: This will disable logging. 396 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 397 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 398 """ 399 400 __slots__ = ( 401 "_token", 402 "_session", 403 "_lock", 404 "_max_retries", 405 "_client_secret", 406 "_client_id", 407 "_metadata", 408 "_max_rate_limit_retries", 409 ) 410 411 def __init__( 412 self, 413 token: str, 414 /, 415 client_secret: typing.Optional[str] = None, 416 client_id: typing.Optional[int] = None, 417 *, 418 max_retries: int = 4, 419 max_ratelimit_retries: int = 3, 420 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 421 ) -> None: 422 self._session: typing.Optional[_Session] = None 423 self._lock: typing.Optional[asyncio.Lock] = None 424 self._client_secret = client_secret 425 self._client_id = client_id 426 self._token: str = token 427 self._max_retries = max_retries 428 self._max_rate_limit_retries = max_ratelimit_retries 429 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 430 431 self._set_debug_level(enable_debugging) 432 433 @property 434 def client_id(self) -> typing.Optional[int]: 435 return self._client_id 436 437 @property 438 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 439 return self._metadata 440 441 @property 442 def is_alive(self) -> bool: 443 return self._session is not None 444 445 @typing.final 446 async def close(self) -> None: 447 if self._session is not None: 448 await self._session.close() 449 self._session = None 450 451 @typing.final 452 def enable_debugging( 453 self, 454 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 455 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 456 /, 457 ) -> None: 458 self._set_debug_level(level, file) 459 460 @typing.final 461 async def static_request( 462 self, 463 method: typing.Union[RequestMethod, str], 464 path: str, 465 *, 466 auth: typing.Optional[str] = None, 467 json: typing.Optional[dict[str, typing.Any]] = None, 468 ) -> ResponseSig: 469 return await self._request(method, path, auth=auth, json=json) 470 471 @typing.final 472 def build_oauth2_url( 473 self, client_id: typing.Optional[int] = None 474 ) -> typing.Optional[str]: 475 client_id = client_id or self._client_id 476 if client_id is None: 477 return None 478 479 return url.OAUTH2_EP_BUILDER.format( 480 oauth_endpoint=url.OAUTH_EP, 481 client_id=client_id, 482 uuid=_uuid(), 483 ) 484 485 def _open(self) -> _Session: 486 """Open a new client session. This is called internally with contextmanager usage.""" 487 asyncio.get_running_loop() 488 if self._session is None: 489 self._session = _Session.create( 490 owner=False, 491 raise_status=False, 492 connect=None, 493 socket_read=None, 494 socket_connect=None, 495 ) 496 return self._session 497 498 @staticmethod 499 def _set_debug_level( 500 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 501 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 502 ) -> None: 503 504 file_handler = logging.FileHandler(file, mode="w") if file else None 505 if level == "TRACE" or level == TRACE: 506 logging.basicConfig( 507 level=TRACE, handlers=[file_handler] if file_handler else None 508 ) 509 510 elif level: 511 logging.basicConfig( 512 level=logging.DEBUG, handlers=[file_handler] if file_handler else None 513 ) 514 515 async def _request( 516 self, 517 method: typing.Union[RequestMethod, str], 518 route: str, 519 *, 520 base: bool = False, 521 oauth2: bool = False, 522 auth: typing.Optional[str] = None, 523 unwrapping: typing.Literal["json", "read"] = "json", 524 json: typing.Optional[dict[str, typing.Any]] = None, 525 headers: typing.Optional[dict[str, typing.Any]] = None, 526 data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None, 527 ) -> ResponseSig: 528 529 retries: int = 0 530 session = self._open() 531 headers = headers or {} 532 533 headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT) 534 headers["X-API-KEY"] = self._token 535 536 if auth is not None: 537 headers[_AUTH_HEADER] = f"Bearer {auth}" 538 539 # Handling endpoints 540 endpoint = url.BASE 541 542 if not base: 543 endpoint = endpoint + url.REST_EP 544 545 if oauth2: 546 headers["Content-Type"] = "application/x-www-form-urlencoded" 547 endpoint = endpoint + url.TOKEN_EP 548 549 if self._lock is None: 550 self._lock = asyncio.Lock() 551 552 while True: 553 try: 554 async with (stack := contextlib.AsyncExitStack()): 555 await stack.enter_async_context(self._lock) 556 557 # We make the request here. 558 taken_time = time.monotonic() 559 response = await stack.enter_async_context( 560 session.client_session.request( 561 method=method, 562 url=f"{endpoint}/{route}", 563 json=json, 564 headers=headers, 565 data=data, 566 ) 567 ) 568 response_time = (time.monotonic() - taken_time) * 1_000 569 570 _LOG.debug( 571 "%s %s %s Time %.4fms", 572 method, 573 f"{endpoint}/{route}", 574 f"{response.status} {response.reason}", 575 response_time, 576 ) 577 578 await self._handle_ratelimit( 579 response, method, route, self._max_rate_limit_retries 580 ) 581 582 if response.status == http.HTTPStatus.NO_CONTENT: 583 return None 584 585 if 300 > response.status >= 200: 586 if unwrapping == "read": 587 # We need to read the bytes for the manifest response. 588 return await response.read() 589 590 if response.content_type == _APP_JSON: 591 json_data = await response.json() 592 593 _LOG.debug( 594 "%s %s %s Time %.4fms", 595 method, 596 f"{endpoint}/{route}", 597 f"{response.status} {response.reason}", 598 response_time, 599 ) 600 601 if _LOG.isEnabledFor(TRACE): 602 headers.update(response.headers) 603 604 _LOG.log( 605 TRACE, 606 "%s", 607 error.stringify_http_message(headers), 608 ) 609 610 # Return the response. 611 # oauth2 responses are not packed inside a Response object. 612 if oauth2: 613 return json_data # type: ignore[no-any-return] 614 615 return json_data["Response"] # type: ignore[no-any-return] 616 617 if ( 618 response.status in _RETRY_5XX 619 and retries < self._max_retries # noqa: W503 620 ): 621 backoff_ = backoff.ExponentialBackOff(maximum=6) 622 sleep_time = next(backoff_) 623 _LOG.warning( 624 "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i", 625 response.status, 626 response.reason, 627 sleep_time, 628 self._max_retries - retries, 629 ) 630 631 retries += 1 632 await asyncio.sleep(sleep_time) 633 continue 634 635 raise await error.raise_error(response) 636 # eol 637 except _Dyn: 638 continue 639 640 if not typing.TYPE_CHECKING: 641 642 def __enter__(self) -> typing.NoReturn: 643 cls = type(self) 644 raise TypeError( 645 f"{cls.__qualname__} is async only, use 'async with' instead." 646 ) 647 648 def __exit__( 649 self, 650 exception_type: typing.Optional[type[BaseException]], 651 exception: typing.Optional[BaseException], 652 exception_traceback: typing.Optional[types.TracebackType], 653 ) -> None: 654 ... 655 656 async def __aenter__(self) -> RESTClient: 657 self._open() 658 return self 659 660 async def __aexit__( 661 self, 662 exception_type: typing.Optional[type[BaseException]], 663 exception: typing.Optional[BaseException], 664 exception_traceback: typing.Optional[types.TracebackType], 665 ) -> None: 666 await self.close() 667 668 # We don't want this to be super complicated. 669 @staticmethod 670 @typing.final 671 async def _handle_ratelimit( 672 response: aiohttp.ClientResponse, 673 method: str, 674 route: str, 675 max_ratelimit_retries: int = 3, 676 ) -> None: 677 678 if response.status != http.HTTPStatus.TOO_MANY_REQUESTS: 679 return 680 681 if response.content_type != _APP_JSON: 682 raise error.HTTPError( 683 f"Being ratelimited on non JSON request, {response.content_type}.", 684 http.HTTPStatus.TOO_MANY_REQUESTS, 685 ) 686 687 count: int = 0 688 json: typedefs.JSONObject = await response.json() 689 retry_after = float(json["ThrottleSeconds"]) 690 691 while True: 692 if count == max_ratelimit_retries: 693 raise _Dyn 694 695 if retry_after <= 0: 696 # We sleep for a little bit to avoid funky behavior. 697 sleep_time = float(random.random() + 0.93) / 2 698 699 _LOG.warning( 700 "We're being ratelimited with method %s route %s. Sleeping for %.2fs.", 701 method, 702 route, 703 sleep_time, 704 ) 705 count += 1 706 await asyncio.sleep(sleep_time) 707 continue 708 709 raise error.RateLimitedError( 710 body=json, 711 url=str(response.real_url), 712 retry_after=retry_after, 713 ) 714 715 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 716 717 if not isinstance(self._client_id, int): 718 raise TypeError( 719 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 720 ) 721 722 if not isinstance(self._client_secret, str): 723 raise TypeError( 724 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 725 ) 726 727 headers = { 728 "client_secret": self._client_secret, 729 } 730 731 data = ( 732 f"grant_type=authorization_code&code={code}" 733 f"&client_id={self._client_id}&client_secret={self._client_secret}" 734 ) 735 736 response = await self._request( 737 RequestMethod.POST, "", headers=headers, data=data, oauth2=True 738 ) 739 assert isinstance(response, dict) 740 return builders.OAuth2Response.build_response(response) 741 742 async def refresh_access_token( 743 self, refresh_token: str, / 744 ) -> builders.OAuth2Response: 745 if not isinstance(self._client_id, int): 746 raise TypeError( 747 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 748 ) 749 750 if not isinstance(self._client_secret, str): 751 raise TypeError( 752 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 753 ) 754 755 data = { 756 "grant_type": "refresh_token", 757 "refresh_token": refresh_token, 758 "client_id": self._client_id, 759 "client_secret": self._client_secret, 760 "Content-Type": "application/x-www-form-urlencoded", 761 } 762 763 response = await self._request(RequestMethod.POST, "", data=data, oauth2=True) 764 assert isinstance(response, dict) 765 return builders.OAuth2Response.build_response(response) 766 767 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 768 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 769 resp = await self._request( 770 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 771 ) 772 assert isinstance(resp, dict) 773 return resp 774 775 async def fetch_user_themes(self) -> typedefs.JSONArray: 776 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 777 resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/") 778 assert isinstance(resp, list) 779 return resp 780 781 async def fetch_membership_from_id( 782 self, 783 id: int, 784 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 785 /, 786 ) -> typedefs.JSONObject: 787 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 788 resp = await self._request( 789 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 790 ) 791 assert isinstance(resp, dict) 792 return resp 793 794 async def fetch_player( 795 self, 796 name: str, 797 code: int, 798 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 799 /, 800 ) -> typedefs.JSONArray: 801 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 802 resp = await self._request( 803 RequestMethod.POST, 804 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 805 json={"displayName": name, "displayNameCode": code}, 806 ) 807 assert isinstance(resp, list) 808 return resp 809 810 async def search_users(self, name: str, /) -> typedefs.JSONObject: 811 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 812 resp = await self._request( 813 RequestMethod.POST, 814 "User/Search/GlobalName/0", 815 json={"displayNamePrefix": name}, 816 ) 817 assert isinstance(resp, dict) 818 return resp 819 820 async def fetch_clan_from_id( 821 self, id: int, /, access_token: typing.Optional[str] = None 822 ) -> typedefs.JSONObject: 823 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 824 resp = await self._request( 825 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 826 ) 827 assert isinstance(resp, dict) 828 return resp 829 830 async def fetch_clan( 831 self, 832 name: str, 833 /, 834 access_token: typing.Optional[str] = None, 835 *, 836 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 837 ) -> typedefs.JSONObject: 838 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 839 resp = await self._request( 840 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 841 ) 842 assert isinstance(resp, dict) 843 return resp 844 845 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 846 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 847 resp = await self._request( 848 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 849 ) 850 assert isinstance(resp, dict) 851 return resp 852 853 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 854 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 855 resp = await self._request( 856 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 857 ) 858 assert isinstance(resp, list) 859 return resp 860 861 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 862 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 863 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 864 assert isinstance(resp, dict) 865 return resp 866 867 async def fetch_character( 868 self, 869 member_id: int, 870 membership_type: typedefs.IntAnd[enums.MembershipType], 871 character_id: int, 872 components: list[enums.ComponentType], 873 auth: typing.Optional[str] = None, 874 ) -> typedefs.JSONObject: 875 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 876 collector = _collect_components(components) 877 response = await self._request( 878 RequestMethod.GET, 879 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 880 f"Character/{character_id}/?components={collector}", 881 auth=auth, 882 ) 883 assert isinstance(response, dict) 884 return response 885 886 async def fetch_activities( 887 self, 888 member_id: int, 889 character_id: int, 890 mode: typedefs.IntAnd[enums.GameMode], 891 membership_type: typedefs.IntAnd[ 892 enums.MembershipType 893 ] = enums.MembershipType.ALL, 894 *, 895 page: int = 0, 896 limit: int = 1, 897 ) -> typedefs.JSONObject: 898 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 899 resp = await self._request( 900 RequestMethod.GET, 901 f"Destiny2/{int(membership_type)}/Account/" 902 f"{member_id}/Character/{character_id}/Stats/Activities" 903 f"/?mode={int(mode)}&count={limit}&page={page}", 904 ) 905 assert isinstance(resp, dict) 906 return resp 907 908 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 909 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 910 resp = await self._request( 911 RequestMethod.GET, 912 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 913 ) 914 assert isinstance(resp, dict) 915 return resp 916 917 async def fetch_profile( 918 self, 919 membership_id: int, 920 type: typedefs.IntAnd[enums.MembershipType], 921 components: list[enums.ComponentType], 922 auth: typing.Optional[str] = None, 923 ) -> typedefs.JSONObject: 924 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 925 collector = _collect_components(components) 926 response = await self._request( 927 RequestMethod.GET, 928 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 929 auth=auth, 930 ) 931 assert isinstance(response, dict) 932 return response 933 934 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 935 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 936 response = await self._request( 937 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 938 ) 939 assert isinstance(response, dict) 940 return response 941 942 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 943 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 944 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 945 assert isinstance(resp, dict) 946 return resp 947 948 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 949 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 950 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 951 assert isinstance(resp, dict) 952 return resp 953 954 async def fetch_groups_for_member( 955 self, 956 member_id: int, 957 member_type: typedefs.IntAnd[enums.MembershipType], 958 /, 959 *, 960 filter: int = 0, 961 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 962 ) -> typedefs.JSONObject: 963 resp = await self._request( 964 RequestMethod.GET, 965 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 966 ) 967 assert isinstance(resp, dict) 968 return resp 969 970 async def fetch_potential_groups_for_member( 971 self, 972 member_id: int, 973 member_type: typedefs.IntAnd[enums.MembershipType], 974 /, 975 *, 976 filter: int = 0, 977 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 978 ) -> typedefs.JSONObject: 979 resp = await self._request( 980 RequestMethod.GET, 981 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 982 ) 983 assert isinstance(resp, dict) 984 return resp 985 986 async def fetch_clan_members( 987 self, 988 clan_id: int, 989 /, 990 *, 991 name: typing.Optional[str] = None, 992 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 993 ) -> typedefs.JSONObject: 994 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 995 resp = await self._request( 996 RequestMethod.GET, 997 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 998 ) 999 assert isinstance(resp, dict) 1000 return resp 1001 1002 async def fetch_hardlinked_credentials( 1003 self, 1004 credential: int, 1005 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 1006 /, 1007 ) -> typedefs.JSONObject: 1008 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1009 resp = await self._request( 1010 RequestMethod.GET, 1011 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 1012 ) 1013 assert isinstance(resp, dict) 1014 return resp 1015 1016 async def fetch_user_credentials( 1017 self, access_token: str, membership_id: int, / 1018 ) -> typedefs.JSONArray: 1019 resp = await self._request( 1020 RequestMethod.GET, 1021 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 1022 auth=access_token, 1023 ) 1024 assert isinstance(resp, list) 1025 return resp 1026 1027 async def insert_socket_plug( 1028 self, 1029 action_token: str, 1030 /, 1031 instance_id: int, 1032 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1033 character_id: int, 1034 membership_type: typedefs.IntAnd[enums.MembershipType], 1035 ) -> typedefs.JSONObject: 1036 1037 if isinstance(plug, builders.PlugSocketBuilder): 1038 plug = plug.collect() 1039 1040 body = { 1041 "actionToken": action_token, 1042 "itemInstanceId": instance_id, 1043 "plug": plug, 1044 "characterId": character_id, 1045 "membershipType": int(membership_type), 1046 } 1047 resp = await self._request( 1048 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 1049 ) 1050 assert isinstance(resp, dict) 1051 return resp 1052 1053 async def insert_socket_plug_free( 1054 self, 1055 access_token: str, 1056 /, 1057 instance_id: int, 1058 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1059 character_id: int, 1060 membership_type: typedefs.IntAnd[enums.MembershipType], 1061 ) -> typedefs.JSONObject: 1062 1063 if isinstance(plug, builders.PlugSocketBuilder): 1064 plug = plug.collect() 1065 1066 body = { 1067 "itemInstanceId": instance_id, 1068 "plug": plug, 1069 "characterId": character_id, 1070 "membershipType": int(membership_type), 1071 } 1072 resp = await self._request( 1073 RequestMethod.POST, 1074 "Destiny2/Actions/Items/InsertSocketPlugFree", 1075 json=body, 1076 auth=access_token, 1077 ) 1078 assert isinstance(resp, dict) 1079 return resp 1080 1081 async def set_item_lock_state( 1082 self, 1083 access_token: str, 1084 state: bool, 1085 /, 1086 item_id: int, 1087 character_id: int, 1088 membership_type: typedefs.IntAnd[enums.MembershipType], 1089 ) -> int: 1090 body = { 1091 "state": state, 1092 "itemId": item_id, 1093 "characterId": character_id, 1094 "membership_type": int(membership_type), 1095 } 1096 response = await self._request( 1097 RequestMethod.POST, 1098 "Destiny2/Actions/Items/SetLockState", 1099 json=body, 1100 auth=access_token, 1101 ) 1102 assert isinstance(response, int) 1103 return response 1104 1105 async def set_quest_track_state( 1106 self, 1107 access_token: str, 1108 state: bool, 1109 /, 1110 item_id: int, 1111 character_id: int, 1112 membership_type: typedefs.IntAnd[enums.MembershipType], 1113 ) -> int: 1114 body = { 1115 "state": state, 1116 "itemId": item_id, 1117 "characterId": character_id, 1118 "membership_type": int(membership_type), 1119 } 1120 response = await self._request( 1121 RequestMethod.POST, 1122 "Destiny2/Actions/Items/SetTrackedState", 1123 json=body, 1124 auth=access_token, 1125 ) 1126 assert isinstance(response, int) 1127 return response 1128 1129 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1130 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1131 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1132 assert isinstance(path, dict) 1133 return path 1134 1135 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1136 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1137 _ensure_manifest_language(language) 1138 1139 content = await self.fetch_manifest_path() 1140 resp = await self._request( 1141 RequestMethod.GET, 1142 content["mobileWorldContentPaths"][language], 1143 unwrapping="read", 1144 base=True, 1145 ) 1146 assert isinstance(resp, bytes) 1147 return resp 1148 1149 async def download_manifest( 1150 self, 1151 language: str = "en", 1152 name: str = "manifest.sqlite3", 1153 *, 1154 force: bool = False, 1155 ) -> None: 1156 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1157 if os.path.exists(name): 1158 1159 if force: 1160 _LOG.debug("Forcing manifest download.") 1161 os.remove(name) 1162 1163 return await self.download_manifest(language, name, force=force) 1164 1165 else: 1166 raise FileExistsError( 1167 "Manifest file already exists, " 1168 "If you want to force download, set the `force` parameter to `True`." 1169 ) 1170 1171 _LOG.debug("Downloading manifest...") 1172 data_bytes = await self.read_manifest_bytes(language) 1173 await asyncio.get_running_loop().run_in_executor( 1174 None, _write_sqlite_bytes, data_bytes, name 1175 ) 1176 1177 async def download_json_manifest(self, language: str = "en") -> None: 1178 _ensure_manifest_language(language) 1179 1180 _LOG.debug("Downloading manifest JSON...") 1181 1182 content = await self.fetch_manifest_path() 1183 json_bytes = await self._request( 1184 RequestMethod.GET, 1185 content["jsonWorldContentPaths"][language], 1186 unwrapping="read", 1187 base=True, 1188 ) 1189 1190 await asyncio.get_running_loop().run_in_executor( 1191 None, _write_json_bytes, json_bytes 1192 ) 1193 _LOG.debug("Finished downloading manifest JSON.") 1194 1195 async def fetch_manifest_version(self) -> str: 1196 return typing.cast(str, (await self.fetch_manifest_path())["version"]) 1197 1198 @staticmethod 1199 @helpers.deprecated( 1200 since="0.2.6a1", removed_in="0.2.6", use_instead="sqlite3.connect" 1201 ) 1202 def connect_manifest( 1203 path: typing.Optional[pathlib.Path] = None, 1204 connection: type[sqlite3.Connection] = sqlite3.Connection, 1205 ) -> sqlite3.Connection: 1206 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1207 path = path or pathlib.Path("./manifest.sqlite3") 1208 if not path.exists(): 1209 raise FileNotFoundError(f"Manifest in path {path.name} doesn't exists.") 1210 return connection(path.name) 1211 1212 async def fetch_linked_profiles( 1213 self, 1214 member_id: int, 1215 member_type: typedefs.IntAnd[enums.MembershipType], 1216 /, 1217 *, 1218 all: bool = False, 1219 ) -> typedefs.JSONObject: 1220 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1221 resp = await self._request( 1222 RequestMethod.GET, 1223 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1224 ) 1225 assert isinstance(resp, dict) 1226 return resp 1227 1228 async def fetch_clan_banners(self) -> typedefs.JSONObject: 1229 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1230 resp = await self._request( 1231 RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/" 1232 ) 1233 assert isinstance(resp, dict) 1234 return resp 1235 1236 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1237 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1238 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1239 assert isinstance(resp, dict) 1240 return resp 1241 1242 async def fetch_public_milestone_content( 1243 self, milestone_hash: int, / 1244 ) -> typedefs.JSONObject: 1245 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1246 resp = await self._request( 1247 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1248 ) 1249 assert isinstance(resp, dict) 1250 return resp 1251 1252 async def fetch_current_user_memberships( 1253 self, access_token: str, / 1254 ) -> typedefs.JSONObject: 1255 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1256 resp = await self._request( 1257 RequestMethod.GET, 1258 "User/GetMembershipsForCurrentUser/", 1259 auth=access_token, 1260 ) 1261 assert isinstance(resp, dict) 1262 return resp 1263 1264 async def equip_item( 1265 self, 1266 access_token: str, 1267 /, 1268 item_id: int, 1269 character_id: int, 1270 membership_type: typedefs.IntAnd[enums.MembershipType], 1271 ) -> None: 1272 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1273 payload = { 1274 "itemId": item_id, 1275 "characterId": character_id, 1276 "membershipType": int(membership_type), 1277 } 1278 1279 await self._request( 1280 RequestMethod.POST, 1281 "Destiny2/Actions/Items/EquipItem/", 1282 json=payload, 1283 auth=access_token, 1284 ) 1285 1286 async def equip_items( 1287 self, 1288 access_token: str, 1289 /, 1290 item_ids: list[int], 1291 character_id: int, 1292 membership_type: typedefs.IntAnd[enums.MembershipType], 1293 ) -> None: 1294 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1295 payload = { 1296 "itemIds": item_ids, 1297 "characterId": character_id, 1298 "membershipType": int(membership_type), 1299 } 1300 await self._request( 1301 RequestMethod.POST, 1302 "Destiny2/Actions/Items/EquipItems/", 1303 json=payload, 1304 auth=access_token, 1305 ) 1306 1307 async def ban_clan_member( 1308 self, 1309 access_token: str, 1310 /, 1311 group_id: int, 1312 membership_id: int, 1313 membership_type: typedefs.IntAnd[enums.MembershipType], 1314 *, 1315 length: int = 0, 1316 comment: undefined.UndefinedOr[str] = undefined.Undefined, 1317 ) -> None: 1318 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1319 payload = {"comment": str(comment), "length": length} 1320 await self._request( 1321 RequestMethod.POST, 1322 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1323 json=payload, 1324 auth=access_token, 1325 ) 1326 1327 async def unban_clan_member( 1328 self, 1329 access_token: str, 1330 /, 1331 group_id: int, 1332 membership_id: int, 1333 membership_type: typedefs.IntAnd[enums.MembershipType], 1334 ) -> None: 1335 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1336 await self._request( 1337 RequestMethod.POST, 1338 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1339 auth=access_token, 1340 ) 1341 1342 async def kick_clan_member( 1343 self, 1344 access_token: str, 1345 /, 1346 group_id: int, 1347 membership_id: int, 1348 membership_type: typedefs.IntAnd[enums.MembershipType], 1349 ) -> typedefs.JSONObject: 1350 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1351 resp = await self._request( 1352 RequestMethod.POST, 1353 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1354 auth=access_token, 1355 ) 1356 assert isinstance(resp, dict) 1357 return resp 1358 1359 async def edit_clan( 1360 self, 1361 access_token: str, 1362 /, 1363 group_id: int, 1364 *, 1365 name: typedefs.NoneOr[str] = None, 1366 about: typedefs.NoneOr[str] = None, 1367 motto: typedefs.NoneOr[str] = None, 1368 theme: typedefs.NoneOr[str] = None, 1369 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1370 is_public: typedefs.NoneOr[bool] = None, 1371 locale: typedefs.NoneOr[str] = None, 1372 avatar_image_index: typedefs.NoneOr[int] = None, 1373 membership_option: typedefs.NoneOr[ 1374 typedefs.IntAnd[enums.MembershipOption] 1375 ] = None, 1376 allow_chat: typedefs.NoneOr[bool] = None, 1377 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1378 call_sign: typedefs.NoneOr[str] = None, 1379 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1380 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1381 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1382 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1383 ) -> None: 1384 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1385 payload = { 1386 "name": name, 1387 "about": about, 1388 "motto": motto, 1389 "theme": theme, 1390 "tags": tags, 1391 "isPublic": is_public, 1392 "avatarImageIndex": avatar_image_index, 1393 "isPublicTopicAdminOnly": is_public_topic_admin, 1394 "allowChat": allow_chat, 1395 "chatSecurity": chat_security, 1396 "callsign": call_sign, 1397 "homepage": homepage, 1398 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1399 "defaultPublicity": default_publicity, 1400 "locale": locale, 1401 } 1402 if membership_option is not None: 1403 payload["membershipOption"] = int(membership_option) 1404 1405 await self._request( 1406 RequestMethod.POST, 1407 f"GroupV2/{group_id}/Edit", 1408 json=payload, 1409 auth=access_token, 1410 ) 1411 1412 async def edit_clan_options( 1413 self, 1414 access_token: str, 1415 /, 1416 group_id: int, 1417 *, 1418 invite_permissions_override: typedefs.NoneOr[bool] = None, 1419 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1420 host_guided_game_permission_override: typedefs.NoneOr[ 1421 typing.Literal[0, 1, 2] 1422 ] = None, 1423 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1424 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1425 ) -> None: 1426 1427 payload = { 1428 "InvitePermissionOverride": invite_permissions_override, 1429 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1430 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1431 "UpdateBannerPermissionOverride": update_banner_permission_override, 1432 "JoinLevel": int(join_level) if join_level else None, 1433 } 1434 1435 await self._request( 1436 RequestMethod.POST, 1437 f"GroupV2/{group_id}/EditFounderOptions", 1438 json=payload, 1439 auth=access_token, 1440 ) 1441 1442 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1443 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1444 resp = await self._request( 1445 RequestMethod.GET, 1446 "Social/Friends/", 1447 auth=access_token, 1448 ) 1449 assert isinstance(resp, dict) 1450 return resp 1451 1452 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1453 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1454 resp = await self._request( 1455 RequestMethod.GET, 1456 "Social/Friends/Requests", 1457 auth=access_token, 1458 ) 1459 assert isinstance(resp, dict) 1460 return resp 1461 1462 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1463 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1464 await self._request( 1465 RequestMethod.POST, 1466 f"Social/Friends/Requests/Accept/{member_id}", 1467 auth=access_token, 1468 ) 1469 1470 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1471 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1472 await self._request( 1473 RequestMethod.POST, 1474 f"Social/Friends/Add/{member_id}", 1475 auth=access_token, 1476 ) 1477 1478 async def decline_friend_request( 1479 self, access_token: str, /, member_id: int 1480 ) -> None: 1481 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1482 await self._request( 1483 RequestMethod.POST, 1484 f"Social/Friends/Requests/Decline/{member_id}", 1485 auth=access_token, 1486 ) 1487 1488 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1489 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1490 await self._request( 1491 RequestMethod.POST, 1492 f"Social/Friends/Remove/{member_id}", 1493 auth=access_token, 1494 ) 1495 1496 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1497 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1498 await self._request( 1499 RequestMethod.POST, 1500 f"Social/Friends/Requests/Remove/{member_id}", 1501 auth=access_token, 1502 ) 1503 1504 async def approve_all_pending_group_users( 1505 self, 1506 access_token: str, 1507 /, 1508 group_id: int, 1509 message: undefined.UndefinedOr[str] = undefined.Undefined, 1510 ) -> None: 1511 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1512 await self._request( 1513 RequestMethod.POST, 1514 f"GroupV2/{group_id}/Members/ApproveAll", 1515 auth=access_token, 1516 json={"message": str(message)}, 1517 ) 1518 1519 async def deny_all_pending_group_users( 1520 self, 1521 access_token: str, 1522 /, 1523 group_id: int, 1524 *, 1525 message: undefined.UndefinedOr[str] = undefined.Undefined, 1526 ) -> None: 1527 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1528 await self._request( 1529 RequestMethod.POST, 1530 f"GroupV2/{group_id}/Members/DenyAll", 1531 auth=access_token, 1532 json={"message": str(message)}, 1533 ) 1534 1535 async def add_optional_conversation( 1536 self, 1537 access_token: str, 1538 /, 1539 group_id: int, 1540 *, 1541 name: undefined.UndefinedOr[str] = undefined.Undefined, 1542 security: typing.Literal[0, 1] = 0, 1543 ) -> None: 1544 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1545 payload = {"chatName": str(name), "chatSecurity": security} 1546 await self._request( 1547 RequestMethod.POST, 1548 f"GroupV2/{group_id}/OptionalConversations/Add", 1549 json=payload, 1550 auth=access_token, 1551 ) 1552 1553 async def edit_optional_conversation( 1554 self, 1555 access_token: str, 1556 /, 1557 group_id: int, 1558 conversation_id: int, 1559 *, 1560 name: undefined.UndefinedOr[str] = undefined.Undefined, 1561 security: typing.Literal[0, 1] = 0, 1562 enable_chat: bool = False, 1563 ) -> None: 1564 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1565 payload = { 1566 "chatEnabled": enable_chat, 1567 "chatName": str(name), 1568 "chatSecurity": security, 1569 } 1570 await self._request( 1571 RequestMethod.POST, 1572 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1573 json=payload, 1574 auth=access_token, 1575 ) 1576 1577 async def transfer_item( 1578 self, 1579 access_token: str, 1580 /, 1581 item_id: int, 1582 item_hash: int, 1583 character_id: int, 1584 member_type: typedefs.IntAnd[enums.MembershipType], 1585 *, 1586 stack_size: int = 1, 1587 vault: bool = False, 1588 ) -> None: 1589 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1590 payload = { 1591 "characterId": character_id, 1592 "membershipType": int(member_type), 1593 "itemId": item_id, 1594 "itemReferenceHash": item_hash, 1595 "stackSize": stack_size, 1596 "transferToVault": vault, 1597 } 1598 await self._request( 1599 RequestMethod.POST, 1600 "Destiny2/Actions/Items/TransferItem", 1601 json=payload, 1602 auth=access_token, 1603 ) 1604 1605 async def pull_item( 1606 self, 1607 access_token: str, 1608 /, 1609 item_id: int, 1610 item_hash: int, 1611 character_id: int, 1612 member_type: typedefs.IntAnd[enums.MembershipType], 1613 *, 1614 stack_size: int = 1, 1615 vault: bool = False, 1616 ) -> None: 1617 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1618 payload = { 1619 "characterId": character_id, 1620 "membershipType": int(member_type), 1621 "itemId": item_id, 1622 "itemReferenceHash": item_hash, 1623 "stackSize": stack_size, 1624 "transferToVault": vault, 1625 } 1626 await self._request( 1627 RequestMethod.POST, 1628 "Destiny2/Actions/Items/PullFromPostmaster", 1629 json=payload, 1630 auth=access_token, 1631 ) 1632 1633 async def fetch_fireteams( 1634 self, 1635 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1636 *, 1637 platform: typedefs.IntAnd[ 1638 fireteams.FireteamPlatform 1639 ] = fireteams.FireteamPlatform.ANY, 1640 language: typing.Union[ 1641 fireteams.FireteamLanguage, str 1642 ] = fireteams.FireteamLanguage.ALL, 1643 date_range: typedefs.IntAnd[ 1644 fireteams.FireteamDate 1645 ] = fireteams.FireteamDate.ALL, 1646 page: int = 0, 1647 slots_filter: int = 0, 1648 ) -> typedefs.JSONObject: 1649 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1650 resp = await self._request( 1651 RequestMethod.GET, 1652 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1653 ) 1654 assert isinstance(resp, dict) 1655 return resp 1656 1657 async def fetch_avaliable_clan_fireteams( 1658 self, 1659 access_token: str, 1660 group_id: int, 1661 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1662 *, 1663 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1664 language: typing.Union[fireteams.FireteamLanguage, str], 1665 date_range: typedefs.IntAnd[ 1666 fireteams.FireteamDate 1667 ] = fireteams.FireteamDate.ALL, 1668 page: int = 0, 1669 public_only: bool = False, 1670 slots_filter: int = 0, 1671 ) -> typedefs.JSONObject: 1672 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1673 resp = await self._request( 1674 RequestMethod.GET, 1675 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1676 json={"langFilter": str(language)}, 1677 auth=access_token, 1678 ) 1679 assert isinstance(resp, dict) 1680 return resp 1681 1682 async def fetch_clan_fireteam( 1683 self, access_token: str, fireteam_id: int, group_id: int 1684 ) -> typedefs.JSONObject: 1685 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1686 resp = await self._request( 1687 RequestMethod.GET, 1688 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1689 auth=access_token, 1690 ) 1691 assert isinstance(resp, dict) 1692 return resp 1693 1694 async def fetch_my_clan_fireteams( 1695 self, 1696 access_token: str, 1697 group_id: int, 1698 *, 1699 include_closed: bool = True, 1700 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1701 language: typing.Union[fireteams.FireteamLanguage, str], 1702 filtered: bool = True, 1703 page: int = 0, 1704 ) -> typedefs.JSONObject: 1705 payload = {"groupFilter": filtered, "langFilter": str(language)} 1706 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1707 resp = await self._request( 1708 RequestMethod.GET, 1709 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1710 json=payload, 1711 auth=access_token, 1712 ) 1713 assert isinstance(resp, dict) 1714 return resp 1715 1716 async def fetch_private_clan_fireteams( 1717 self, access_token: str, group_id: int, / 1718 ) -> int: 1719 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1720 resp = await self._request( 1721 RequestMethod.GET, 1722 f"Fireteam/Clan/{group_id}/ActiveCount", 1723 auth=access_token, 1724 ) 1725 assert isinstance(resp, int) 1726 return resp 1727 1728 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1729 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1730 resp = await self._request( 1731 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1732 ) 1733 assert isinstance(resp, dict) 1734 return resp 1735 1736 async def search_entities( 1737 self, name: str, entity_type: str, *, page: int = 0 1738 ) -> typedefs.JSONObject: 1739 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1740 resp = await self._request( 1741 RequestMethod.GET, 1742 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1743 json={"page": page}, 1744 ) 1745 assert isinstance(resp, dict) 1746 return resp 1747 1748 async def fetch_unique_weapon_history( 1749 self, 1750 membership_id: int, 1751 character_id: int, 1752 membership_type: typedefs.IntAnd[enums.MembershipType], 1753 ) -> typedefs.JSONObject: 1754 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1755 resp = await self._request( 1756 RequestMethod.GET, 1757 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1758 ) 1759 assert isinstance(resp, dict) 1760 return resp 1761 1762 async def fetch_item( 1763 self, 1764 member_id: int, 1765 item_id: int, 1766 membership_type: typedefs.IntAnd[enums.MembershipType], 1767 components: list[enums.ComponentType], 1768 ) -> typedefs.JSONObject: 1769 collector = _collect_components(components) 1770 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1771 resp = await self._request( 1772 RequestMethod.GET, 1773 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1774 ) 1775 assert isinstance(resp, dict) 1776 return resp 1777 1778 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1779 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1780 resp = await self._request( 1781 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1782 ) 1783 assert isinstance(resp, dict) 1784 return resp 1785 1786 async def fetch_available_locales(self) -> typedefs.JSONObject: 1787 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1788 resp = await self._request( 1789 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1790 ) 1791 assert isinstance(resp, dict) 1792 return resp 1793 1794 async def fetch_common_settings(self) -> typedefs.JSONObject: 1795 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1796 resp = await self._request(RequestMethod.GET, "Settings") 1797 assert isinstance(resp, dict) 1798 return resp 1799 1800 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1801 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1802 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1803 assert isinstance(resp, dict) 1804 return resp 1805 1806 async def fetch_global_alerts( 1807 self, *, include_streaming: bool = False 1808 ) -> typedefs.JSONArray: 1809 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1810 resp = await self._request( 1811 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1812 ) 1813 assert isinstance(resp, list) 1814 return resp 1815 1816 async def awainitialize_request( 1817 self, 1818 access_token: str, 1819 type: typing.Literal[0, 1], 1820 membership_type: typedefs.IntAnd[enums.MembershipType], 1821 /, 1822 *, 1823 affected_item_id: typing.Optional[int] = None, 1824 character_id: typing.Optional[int] = None, 1825 ) -> typedefs.JSONObject: 1826 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1827 1828 body = {"type": type, "membershipType": int(membership_type)} 1829 1830 if affected_item_id is not None: 1831 body["affectedItemId"] = affected_item_id 1832 1833 if character_id is not None: 1834 body["characterId"] = character_id 1835 1836 resp = await self._request( 1837 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1838 ) 1839 assert isinstance(resp, dict) 1840 return resp 1841 1842 async def awaget_action_token( 1843 self, access_token: str, correlation_id: str, / 1844 ) -> typedefs.JSONObject: 1845 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1846 resp = await self._request( 1847 RequestMethod.POST, 1848 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1849 auth=access_token, 1850 ) 1851 assert isinstance(resp, dict) 1852 return resp 1853 1854 async def awa_provide_authorization_result( 1855 self, 1856 access_token: str, 1857 selection: int, 1858 correlation_id: str, 1859 nonce: collections.MutableSequence[typing.Union[str, bytes]], 1860 ) -> int: 1861 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1862 1863 body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce} 1864 1865 resp = await self._request( 1866 RequestMethod.POST, 1867 "Destiny2/Awa/AwaProvideAuthorizationResult", 1868 json=body, 1869 auth=access_token, 1870 ) 1871 assert isinstance(resp, int) 1872 return resp 1873 1874 async def fetch_vendors( 1875 self, 1876 access_token: str, 1877 character_id: int, 1878 membership_id: int, 1879 membership_type: typedefs.IntAnd[enums.MembershipType], 1880 /, 1881 components: list[enums.ComponentType], 1882 filter: typing.Optional[int] = None, 1883 ) -> typedefs.JSONObject: 1884 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1885 components_ = _collect_components(components) 1886 route = ( 1887 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1888 f"/Character/{character_id}/Vendors/?components={components_}" 1889 ) 1890 1891 if filter is not None: 1892 route = route + f"&filter={filter}" 1893 1894 resp = await self._request( 1895 RequestMethod.GET, 1896 route, 1897 auth=access_token, 1898 ) 1899 assert isinstance(resp, dict) 1900 return resp 1901 1902 async def fetch_vendor( 1903 self, 1904 access_token: str, 1905 character_id: int, 1906 membership_id: int, 1907 membership_type: typedefs.IntAnd[enums.MembershipType], 1908 vendor_hash: int, 1909 /, 1910 components: list[enums.ComponentType], 1911 ) -> typedefs.JSONObject: 1912 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1913 components_ = _collect_components(components) 1914 resp = await self._request( 1915 RequestMethod.GET, 1916 ( 1917 f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}" 1918 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1919 ), 1920 auth=access_token, 1921 ) 1922 assert isinstance(resp, dict) 1923 return resp 1924 1925 async def fetch_application_api_usage( 1926 self, 1927 access_token: str, 1928 application_id: int, 1929 /, 1930 *, 1931 start: typing.Optional[datetime.datetime] = None, 1932 end: typing.Optional[datetime.datetime] = None, 1933 ) -> typedefs.JSONObject: 1934 1935 end_date, start_date = time.parse_date_range(end, start) 1936 resp = await self._request( 1937 RequestMethod.GET, 1938 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1939 auth=access_token, 1940 ) 1941 assert isinstance(resp, dict) 1942 return resp 1943 1944 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1945 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1946 assert isinstance(resp, list) 1947 return resp 1948 1949 async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject: 1950 resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/") 1951 assert isinstance(resp, dict) 1952 return resp 1953 1954 async def fetch_content_by_id( 1955 self, id: int, locale: str, /, *, head: bool = False 1956 ) -> typedefs.JSONObject: 1957 resp = await self._request( 1958 RequestMethod.GET, 1959 f"Content/GetContentById/{id}/{locale}/", 1960 json={"head": head}, 1961 ) 1962 assert isinstance(resp, dict) 1963 return resp 1964 1965 async def fetch_content_by_tag_and_type( 1966 self, locale: str, tag: str, type: str, *, head: bool = False 1967 ) -> typedefs.JSONObject: 1968 resp = await self._request( 1969 RequestMethod.GET, 1970 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1971 json={"head": head}, 1972 ) 1973 assert isinstance(resp, dict) 1974 return resp 1975 1976 async def search_content_with_text( 1977 self, 1978 locale: str, 1979 /, 1980 content_type: str, 1981 search_text: str, 1982 tag: str, 1983 *, 1984 page: undefined.UndefinedOr[int] = undefined.Undefined, 1985 source: undefined.UndefinedOr[str] = undefined.Undefined, 1986 ) -> typedefs.JSONObject: 1987 1988 body: typedefs.JSONObject = {} 1989 1990 body["ctype"] = content_type 1991 body["searchtext"] = search_text 1992 body["tag"] = tag 1993 1994 if page is not undefined.Undefined: 1995 body["currentpage"] = page 1996 else: 1997 body["currentpage"] = 1 1998 1999 if source is not undefined.Undefined: 2000 body["source"] = source 2001 else: 2002 source = "" 2003 resp = await self._request( 2004 RequestMethod.GET, f"Content/Search/{locale}/", json=body 2005 ) 2006 assert isinstance(resp, dict) 2007 return resp 2008 2009 async def search_content_by_tag_and_type( 2010 self, 2011 locale: str, 2012 tag: str, 2013 type: str, 2014 *, 2015 page: undefined.UndefinedOr[int] = undefined.Undefined, 2016 ) -> typedefs.JSONObject: 2017 body: typedefs.JSONObject = {} 2018 body["currentpage"] = 1 if page is undefined.Undefined else page 2019 resp = await self._request( 2020 RequestMethod.GET, 2021 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 2022 json=body, 2023 ) 2024 assert isinstance(resp, dict) 2025 return resp 2026 2027 async def search_help_articles( 2028 self, text: str, size: str, / 2029 ) -> typedefs.JSONObject: 2030 resp = await self._request( 2031 RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/" 2032 ) 2033 assert isinstance(resp, dict) 2034 return resp 2035 2036 async def fetch_topics_page( 2037 self, 2038 category_filter: int, 2039 group: int, 2040 date_filter: int, 2041 sort: typing.Union[str, bytes], 2042 *, 2043 page: undefined.UndefinedOr[int] = undefined.Undefined, 2044 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2045 tag_filter: undefined.UndefinedOr[str] = undefined.Undefined, 2046 ) -> typedefs.JSONObject: 2047 2048 body: typedefs.JSONObject = {} 2049 if locales is not undefined.Undefined: 2050 body["locales"] = ",".join(str(locales)) 2051 else: 2052 body["locales"] = ",".join([]) 2053 2054 if tag_filter is not undefined.Undefined: 2055 body["tagstring"] = tag_filter 2056 else: 2057 body["tagstring"] = "" 2058 2059 page = 0 if page is not undefined.Undefined else page 2060 2061 resp = await self._request( 2062 RequestMethod.GET, 2063 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 2064 json=body, 2065 ) 2066 assert isinstance(resp, dict) 2067 return resp 2068 2069 async def fetch_core_topics_page( 2070 self, 2071 category_filter: int, 2072 date_filter: int, 2073 sort: typing.Union[str, bytes], 2074 *, 2075 page: undefined.UndefinedOr[int] = undefined.Undefined, 2076 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2077 ) -> typedefs.JSONObject: 2078 body: typedefs.JSONObject = {} 2079 2080 if locales is not undefined.Undefined: 2081 body["locales"] = ",".join(str(locales)) 2082 else: 2083 body["locales"] = ",".join([]) 2084 2085 resp = await self._request( 2086 RequestMethod.GET, 2087 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}" 2088 f"/{sort!s}/{date_filter}/{category_filter}/", 2089 json=body, 2090 ) 2091 assert isinstance(resp, dict) 2092 return resp 2093 2094 async def fetch_posts_threaded_page( 2095 self, 2096 parent_post: bool, 2097 page: int, 2098 page_size: int, 2099 parent_post_id: int, 2100 reply_size: int, 2101 root_thread_mode: bool, 2102 sort_mode: int, 2103 show_banned: typing.Optional[str] = None, 2104 ) -> typedefs.JSONObject: 2105 resp = await self._request( 2106 RequestMethod.GET, 2107 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 2108 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 2109 json={"showbanned": show_banned}, 2110 ) 2111 assert isinstance(resp, dict) 2112 return resp 2113 2114 async def fetch_posts_threaded_page_from_child( 2115 self, 2116 child_id: bool, 2117 page: int, 2118 page_size: int, 2119 reply_size: int, 2120 root_thread_mode: bool, 2121 sort_mode: int, 2122 show_banned: typing.Optional[str] = None, 2123 ) -> typedefs.JSONObject: 2124 resp = await self._request( 2125 RequestMethod.GET, 2126 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 2127 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 2128 json={"showbanned": show_banned}, 2129 ) 2130 assert isinstance(resp, dict) 2131 return resp 2132 2133 async def fetch_post_and_parent( 2134 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2135 ) -> typedefs.JSONObject: 2136 resp = await self._request( 2137 RequestMethod.GET, 2138 f"Forum/GetPostAndParent/{child_id}/", 2139 json={"showbanned": show_banned}, 2140 ) 2141 assert isinstance(resp, dict) 2142 return resp 2143 2144 async def fetch_posts_and_parent_awaiting( 2145 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2146 ) -> typedefs.JSONObject: 2147 resp = await self._request( 2148 RequestMethod.GET, 2149 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2150 json={"showbanned": show_banned}, 2151 ) 2152 assert isinstance(resp, dict) 2153 return resp 2154 2155 async def fetch_topic_for_content(self, content_id: int, /) -> int: 2156 resp = await self._request( 2157 RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/" 2158 ) 2159 assert isinstance(resp, int) 2160 return resp 2161 2162 async def fetch_forum_tag_suggestions( 2163 self, partial_tag: str, / 2164 ) -> typedefs.JSONObject: 2165 resp = await self._request( 2166 RequestMethod.GET, 2167 "Forum/GetForumTagSuggestions/", 2168 json={"partialtag": partial_tag}, 2169 ) 2170 assert isinstance(resp, dict) 2171 return resp 2172 2173 async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject: 2174 resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/") 2175 assert isinstance(resp, dict) 2176 return resp 2177 2178 async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray: 2179 resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/") 2180 assert isinstance(resp, list) 2181 return resp 2182 2183 async def fetch_recommended_groups( 2184 self, 2185 accecss_token: str, 2186 /, 2187 *, 2188 date_range: int = 0, 2189 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2190 ) -> typedefs.JSONArray: 2191 resp = await self._request( 2192 RequestMethod.POST, 2193 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2194 auth=accecss_token, 2195 ) 2196 assert isinstance(resp, list) 2197 return resp 2198 2199 async def fetch_available_avatars(self) -> collections.Mapping[str, int]: 2200 resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/") 2201 assert isinstance(resp, dict) 2202 return resp 2203 2204 async def fetch_user_clan_invite_setting( 2205 self, 2206 access_token: str, 2207 /, 2208 membership_type: typedefs.IntAnd[enums.MembershipType], 2209 ) -> bool: 2210 resp = await self._request( 2211 RequestMethod.GET, 2212 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2213 auth=access_token, 2214 ) 2215 assert isinstance(resp, bool) 2216 return resp 2217 2218 async def fetch_banned_group_members( 2219 self, access_token: str, group_id: int, /, *, page: int = 1 2220 ) -> typedefs.JSONObject: 2221 resp = await self._request( 2222 RequestMethod.GET, 2223 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2224 auth=access_token, 2225 ) 2226 assert isinstance(resp, dict) 2227 return resp 2228 2229 async def fetch_pending_group_memberships( 2230 self, access_token: str, group_id: int, /, *, current_page: int = 1 2231 ) -> typedefs.JSONObject: 2232 resp = await self._request( 2233 RequestMethod.GET, 2234 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2235 auth=access_token, 2236 ) 2237 assert isinstance(resp, dict) 2238 return resp 2239 2240 async def fetch_invited_group_memberships( 2241 self, access_token: str, group_id: int, /, *, current_page: int = 1 2242 ) -> typedefs.JSONObject: 2243 resp = await self._request( 2244 RequestMethod.GET, 2245 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2246 auth=access_token, 2247 ) 2248 assert isinstance(resp, dict) 2249 return resp 2250 2251 async def invite_member_to_group( 2252 self, 2253 access_token: str, 2254 /, 2255 group_id: int, 2256 membership_id: int, 2257 membership_type: typedefs.IntAnd[enums.MembershipType], 2258 *, 2259 message: undefined.UndefinedOr[str] = undefined.Undefined, 2260 ) -> typedefs.JSONObject: 2261 resp = await self._request( 2262 RequestMethod.POST, 2263 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2264 auth=access_token, 2265 json={"message": str(message)}, 2266 ) 2267 assert isinstance(resp, dict) 2268 return resp 2269 2270 async def cancel_group_member_invite( 2271 self, 2272 access_token: str, 2273 /, 2274 group_id: int, 2275 membership_id: int, 2276 membership_type: typedefs.IntAnd[enums.MembershipType], 2277 ) -> typedefs.JSONObject: 2278 resp = await self._request( 2279 RequestMethod.POST, 2280 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2281 auth=access_token, 2282 ) 2283 assert isinstance(resp, dict) 2284 return resp 2285 2286 async def fetch_historical_definition(self) -> typedefs.JSONObject: 2287 resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/") 2288 assert isinstance(resp, dict) 2289 return resp 2290 2291 async def fetch_historical_stats( 2292 self, 2293 character_id: int, 2294 membership_id: int, 2295 membership_type: typedefs.IntAnd[enums.MembershipType], 2296 day_start: datetime.datetime, 2297 day_end: datetime.datetime, 2298 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2299 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2300 *, 2301 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2302 ) -> typedefs.JSONObject: 2303 2304 end, start = time.parse_date_range(day_end, day_start) 2305 resp = await self._request( 2306 RequestMethod.GET, 2307 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2308 json={ 2309 "dayend": end, 2310 "daystart": start, 2311 "groups": [str(int(group)) for group in groups], 2312 "modes": [str(int(mode)) for mode in modes], 2313 "periodType": int(period_type), 2314 }, 2315 ) 2316 assert isinstance(resp, dict) 2317 return resp 2318 2319 async def fetch_historical_stats_for_account( 2320 self, 2321 membership_id: int, 2322 membership_type: typedefs.IntAnd[enums.MembershipType], 2323 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2324 ) -> typedefs.JSONObject: 2325 resp = await self._request( 2326 RequestMethod.GET, 2327 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2328 json={"groups": [str(int(group)) for group in groups]}, 2329 ) 2330 assert isinstance(resp, dict) 2331 return resp 2332 2333 async def fetch_aggregated_activity_stats( 2334 self, 2335 character_id: int, 2336 membership_id: int, 2337 membership_type: typedefs.IntAnd[enums.MembershipType], 2338 /, 2339 ) -> typedefs.JSONObject: 2340 resp = await self._request( 2341 RequestMethod.GET, 2342 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2343 f"Character/{character_id}/Stats/AggregateActivityStats/", 2344 ) 2345 assert isinstance(resp, dict) 2346 return resp
A RESTful client implementation for Bungie's API.
This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.
This client is also used within aiobungie.Client which deserialize those returned JSON objects
using the factory into Pythonic data classes objects which provide Python functionality.
Example
import aiobungie
async def main():
async with aiobungie.RESTClient("TOKEN") as rest_client:
req = await rest_client.fetch_clan_members(4389205)
clan_members = req['results']
for member in clan_members:
for k, v in member['destinyUserInfo'].items():
print(k, v)
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
411 def __init__( 412 self, 413 token: str, 414 /, 415 client_secret: typing.Optional[str] = None, 416 client_id: typing.Optional[int] = None, 417 *, 418 max_retries: int = 4, 419 max_ratelimit_retries: int = 3, 420 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 421 ) -> None: 422 self._session: typing.Optional[_Session] = None 423 self._lock: typing.Optional[asyncio.Lock] = None 424 self._client_secret = client_secret 425 self._client_id = client_id 426 self._token: str = token 427 self._max_retries = max_retries 428 self._max_rate_limit_retries = max_ratelimit_retries 429 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 430 431 self._set_debug_level(enable_debugging)
A mutable mapping storage for the user's needs.
This mapping is useful for storing any kind of data that the user may need.
Example
import aiobungie
client = aiobungie.RESTClient(…)
async with client:
# Fetch auth tokens and store them
client.metadata["tokens"] = await client.fetch_access_token("code")
# Some other time.
async with client:
# Retrieve the tokens
tokens: aiobungie.OAuth2Response = client.metadata["tokens"]
# Use them to fetch your user.
user = await client.fetch_current_user_memberships(tokens.access_token)
445 @typing.final 446 async def close(self) -> None: 447 if self._session is not None: 448 await self._session.close() 449 self._session = None
Close this REST client session if it was acquired.
451 @typing.final 452 def enable_debugging( 453 self, 454 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 455 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 456 /, 457 ) -> None: 458 self._set_debug_level(level, file)
Enables debugging for the REST calls.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE"|aiobungie.TRACE: This will log the response headers along with the minimal information.
Parameters
- level (
str | bool | int): The level of debugging to enable. - file (
pathlib.Path | str | None): The file path to write the debug logs to. If provided.
460 @typing.final 461 async def static_request( 462 self, 463 method: typing.Union[RequestMethod, str], 464 path: str, 465 *, 466 auth: typing.Optional[str] = None, 467 json: typing.Optional[dict[str, typing.Any]] = None, 468 ) -> ResponseSig: 469 return await self._request(method, path, auth=auth, json=json)
Perform an HTTP request given a valid Bungie endpoint.
Parameters
- method (
aiobungie.RequestMethod | str): The request method, This may beGET,POST,PUT, etc. - path (
str): The Bungie endpoint or path. A path must look something like thisDestiny2/3/Profile/46111239123/... - auth (
str | None): An optional bearer token for methods that requires OAuth2 Authorization header. - json (
dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
aiobungie.rest.ResponseSig: The response payload.
471 @typing.final 472 def build_oauth2_url( 473 self, client_id: typing.Optional[int] = None 474 ) -> typing.Optional[str]: 475 client_id = client_id or self._client_id 476 if client_id is None: 477 return None 478 479 return url.OAUTH2_EP_BUILDER.format( 480 oauth_endpoint=url.OAUTH_EP, 481 client_id=client_id, 482 uuid=_uuid(), 483 )
Builds an OAuth2 URL using the provided user REST/Base client secret/id.
Parameters
- client_id (
int | None): An optional client id to provide, If leftNoneit will roll back to the id passed to theRESTClient, If both isNonethis method will returnNone.
Returns
str | None: If the client id was provided as a parameter or provided inaiobungie.RESTClient, A complete URL will be returned. OtherwiseNonewill be returned.
715 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 716 717 if not isinstance(self._client_id, int): 718 raise TypeError( 719 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 720 ) 721 722 if not isinstance(self._client_secret, str): 723 raise TypeError( 724 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 725 ) 726 727 headers = { 728 "client_secret": self._client_secret, 729 } 730 731 data = ( 732 f"grant_type=authorization_code&code={code}" 733 f"&client_id={self._client_id}&client_secret={self._client_secret}" 734 ) 735 736 response = await self._request( 737 RequestMethod.POST, "", headers=headers, data=data, oauth2=True 738 ) 739 assert isinstance(response, dict) 740 return builders.OAuth2Response.build_response(response)
Makes a POST request and fetch the OAuth2 access_token and refresh token.
Parameters
- code (
str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
Raises
aiobungie.Unauthorized: The passed code was invalid.
742 async def refresh_access_token( 743 self, refresh_token: str, / 744 ) -> builders.OAuth2Response: 745 if not isinstance(self._client_id, int): 746 raise TypeError( 747 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 748 ) 749 750 if not isinstance(self._client_secret, str): 751 raise TypeError( 752 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 753 ) 754 755 data = { 756 "grant_type": "refresh_token", 757 "refresh_token": refresh_token, 758 "client_id": self._client_id, 759 "client_secret": self._client_secret, 760 "Content-Type": "application/x-www-form-urlencoded", 761 } 762 763 response = await self._request(RequestMethod.POST, "", data=data, oauth2=True) 764 assert isinstance(response, dict) 765 return builders.OAuth2Response.build_response(response)
Refresh OAuth2 access token given its refresh token.
Parameters
- refresh_token (
str): The refresh token.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
767 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 768 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 769 resp = await self._request( 770 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 771 ) 772 assert isinstance(resp, dict) 773 return resp
Fetch a Bungie user by their id.
Parameters
- id (
int): The user id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of users objects.
Raises
aiobungie.NotFound: The user was not found.
781 async def fetch_membership_from_id( 782 self, 783 id: int, 784 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 785 /, 786 ) -> typedefs.JSONObject: 787 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 788 resp = await self._request( 789 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 790 ) 791 assert isinstance(resp, dict) 792 return resp
Fetch Bungie user's memberships from their id.
Parameters
- id (
int): The user's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user.
Raises
- aiobungie.NotFound: The requested user was not found.
794 async def fetch_player( 795 self, 796 name: str, 797 code: int, 798 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 799 /, 800 ) -> typedefs.JSONArray: 801 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 802 resp = await self._request( 803 RequestMethod.POST, 804 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 805 json={"displayName": name, "displayNameCode": code}, 806 ) 807 assert isinstance(resp, list) 808 return resp
Fetch a Destiny 2 Player.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
aiobungie.typedefs.JSONArray: A JSON array of the found player's memberships.
Raises
aiobungie.NotFound: The player was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
810 async def search_users(self, name: str, /) -> typedefs.JSONObject: 811 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 812 resp = await self._request( 813 RequestMethod.POST, 814 "User/Search/GlobalName/0", 815 json={"displayNamePrefix": name}, 816 ) 817 assert isinstance(resp, dict) 818 return resp
Search for users by their global name and return all users who share this name.
Parameters
- name (
str): The user name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the found users.
Raises
aiobungie.NotFound: The user(s) was not found.
820 async def fetch_clan_from_id( 821 self, id: int, /, access_token: typing.Optional[str] = None 822 ) -> typedefs.JSONObject: 823 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 824 resp = await self._request( 825 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 826 ) 827 assert isinstance(resp, dict) 828 return resp
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
830 async def fetch_clan( 831 self, 832 name: str, 833 /, 834 access_token: typing.Optional[str] = None, 835 *, 836 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 837 ) -> typedefs.JSONObject: 838 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 839 resp = await self._request( 840 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 841 ) 842 assert isinstance(resp, dict) 843 return resp
Fetch a Clan by its name. This method will return the first clan found with given name name.
Parameters
- name (
str): The clan name.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group type, Default is one.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
845 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 846 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 847 resp = await self._request( 848 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 849 ) 850 assert isinstance(resp, dict) 851 return resp
Fetch the admins and founder members of the clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan admins and founder members.
Raises
aiobungie.NotFound: The clan was not found.
853 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 854 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 855 resp = await self._request( 856 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 857 ) 858 assert isinstance(resp, list) 859 return resp
Fetch a clan's conversations.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the conversations.
861 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 862 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 863 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 864 assert isinstance(resp, dict) 865 return resp
Fetch a Bungie Application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application.
867 async def fetch_character( 868 self, 869 member_id: int, 870 membership_type: typedefs.IntAnd[enums.MembershipType], 871 character_id: int, 872 components: list[enums.ComponentType], 873 auth: typing.Optional[str] = None, 874 ) -> typedefs.JSONObject: 875 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 876 collector = _collect_components(components) 877 response = await self._request( 878 RequestMethod.GET, 879 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 880 f"Character/{character_id}/?components={collector}", 881 auth=auth, 882 ) 883 assert isinstance(response, dict) 884 return response
Fetch a Destiny 2 player's characters.
Parameters
- member_id (
int): A valid bungie member id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type. - character_id (
int): The character id to return. - components (
list[aiobungie.ComponentType]): A list of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the requested character.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
886 async def fetch_activities( 887 self, 888 member_id: int, 889 character_id: int, 890 mode: typedefs.IntAnd[enums.GameMode], 891 membership_type: typedefs.IntAnd[ 892 enums.MembershipType 893 ] = enums.MembershipType.ALL, 894 *, 895 page: int = 0, 896 limit: int = 1, 897 ) -> typedefs.JSONObject: 898 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 899 resp = await self._request( 900 RequestMethod.GET, 901 f"Destiny2/{int(membership_type)}/Account/" 902 f"{member_id}/Character/{character_id}/Stats/Activities" 903 f"/?mode={int(mode)}&count={limit}&page={page}", 904 ) 905 assert isinstance(resp, dict) 906 return resp
Fetch a Destiny 2 activity for the specified user id and character.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Member ship type, if nothing was passed than it will return all. - page (
int): The page number. Default to1 - limit (
int): Limit the returned result. Default to1
Returns
aiobungie.typedefs.JSONObject: A JSON object of the player's activities.
Raises
aiobungie.NotFound: The activity was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
908 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 909 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 910 resp = await self._request( 911 RequestMethod.GET, 912 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 913 ) 914 assert isinstance(resp, dict) 915 return resp
917 async def fetch_profile( 918 self, 919 membership_id: int, 920 type: typedefs.IntAnd[enums.MembershipType], 921 components: list[enums.ComponentType], 922 auth: typing.Optional[str] = None, 923 ) -> typedefs.JSONObject: 924 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 925 collector = _collect_components(components) 926 response = await self._request( 927 RequestMethod.GET, 928 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 929 auth=auth, 930 ) 931 assert isinstance(response, dict) 932 return response
Fetch a bungie profile.
Parameters
- membership_id (
int): The member's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): A valid membership type. - components (
list[aiobungie.ComponentType]): A list of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found profile.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
934 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 935 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 936 response = await self._request( 937 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 938 ) 939 assert isinstance(response, dict) 940 return response
Fetch a Destiny definition item given its type and hash.
Parameters
- type (
str): Entity's type definition. - hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the definition data.
942 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 943 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 944 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 945 assert isinstance(resp, dict) 946 return resp
Fetch a Destiny inventory item entity given a its hash.
Parameters
- hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the inventory item.
948 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 949 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 950 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 951 assert isinstance(resp, dict) 952 return resp
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the objetive data.
954 async def fetch_groups_for_member( 955 self, 956 member_id: int, 957 member_type: typedefs.IntAnd[enums.MembershipType], 958 /, 959 *, 960 filter: int = 0, 961 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 962 ) -> typedefs.JSONObject: 963 resp = await self._request( 964 RequestMethod.GET, 965 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 966 ) 967 assert isinstance(resp, dict) 968 return resp
Fetch the information about the groups for a member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
builsins.int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
970 async def fetch_potential_groups_for_member( 971 self, 972 member_id: int, 973 member_type: typedefs.IntAnd[enums.MembershipType], 974 /, 975 *, 976 filter: int = 0, 977 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 978 ) -> typedefs.JSONObject: 979 resp = await self._request( 980 RequestMethod.GET, 981 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 982 ) 983 assert isinstance(resp, dict) 984 return resp
Get information about the groups that a given member has applied to or been invited to.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
builsins.int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
986 async def fetch_clan_members( 987 self, 988 clan_id: int, 989 /, 990 *, 991 name: typing.Optional[str] = None, 992 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 993 ) -> typedefs.JSONObject: 994 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 995 resp = await self._request( 996 RequestMethod.GET, 997 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 998 ) 999 assert isinstance(resp, dict) 1000 return resp
Fetch all Bungie Clan members.
Parameters
- clan_id (
builsins.int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): An optional clan member's membership type. Default is set toaiobungie.MembershipType.NONEWhich returns the first matched clan member by their name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of clan members.
Raises
aiobungie.NotFound: The clan was not found.
1002 async def fetch_hardlinked_credentials( 1003 self, 1004 credential: int, 1005 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 1006 /, 1007 ) -> typedefs.JSONObject: 1008 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1009 resp = await self._request( 1010 RequestMethod.GET, 1011 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 1012 ) 1013 assert isinstance(resp, dict) 1014 return resp
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.typedefs.IntAnd[aiobungie.CredentialType]): The crededntial type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user hard linked types.
1016 async def fetch_user_credentials( 1017 self, access_token: str, membership_id: int, / 1018 ) -> typedefs.JSONArray: 1019 resp = await self._request( 1020 RequestMethod.GET, 1021 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 1022 auth=access_token, 1023 ) 1024 assert isinstance(resp, list) 1025 return resp
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the returned credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1027 async def insert_socket_plug( 1028 self, 1029 action_token: str, 1030 /, 1031 instance_id: int, 1032 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1033 character_id: int, 1034 membership_type: typedefs.IntAnd[enums.MembershipType], 1035 ) -> typedefs.JSONObject: 1036 1037 if isinstance(plug, builders.PlugSocketBuilder): 1038 plug = plug.collect() 1039 1040 body = { 1041 "actionToken": action_token, 1042 "itemInstanceId": instance_id, 1043 "plug": plug, 1044 "characterId": character_id, 1045 "membershipType": int(membership_type), 1046 } 1047 resp = await self._request( 1048 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 1049 ) 1050 assert isinstance(resp, dict) 1051 return resp
Insert a plug into a socketed item.
OAuth2: AdvancedWriteActions scope is required
Parameters
- action_token (
str): Action token provided by the AwaGetActionToken API call. - instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1053 async def insert_socket_plug_free( 1054 self, 1055 access_token: str, 1056 /, 1057 instance_id: int, 1058 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1059 character_id: int, 1060 membership_type: typedefs.IntAnd[enums.MembershipType], 1061 ) -> typedefs.JSONObject: 1062 1063 if isinstance(plug, builders.PlugSocketBuilder): 1064 plug = plug.collect() 1065 1066 body = { 1067 "itemInstanceId": instance_id, 1068 "plug": plug, 1069 "characterId": character_id, 1070 "membershipType": int(membership_type), 1071 } 1072 resp = await self._request( 1073 RequestMethod.POST, 1074 "Destiny2/Actions/Items/InsertSocketPlugFree", 1075 json=body, 1076 auth=access_token, 1077 ) 1078 assert isinstance(resp, dict) 1079 return resp
Insert a plug into a socketed item. This doesn't require an Action token.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1081 async def set_item_lock_state( 1082 self, 1083 access_token: str, 1084 state: bool, 1085 /, 1086 item_id: int, 1087 character_id: int, 1088 membership_type: typedefs.IntAnd[enums.MembershipType], 1089 ) -> int: 1090 body = { 1091 "state": state, 1092 "itemId": item_id, 1093 "characterId": character_id, 1094 "membership_type": int(membership_type), 1095 } 1096 response = await self._request( 1097 RequestMethod.POST, 1098 "Destiny2/Actions/Items/SetLockState", 1099 json=body, 1100 auth=access_token, 1101 ) 1102 assert isinstance(response, int) 1103 return response
Set the Lock State for an instanced item.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1105 async def set_quest_track_state( 1106 self, 1107 access_token: str, 1108 state: bool, 1109 /, 1110 item_id: int, 1111 character_id: int, 1112 membership_type: typedefs.IntAnd[enums.MembershipType], 1113 ) -> int: 1114 body = { 1115 "state": state, 1116 "itemId": item_id, 1117 "characterId": character_id, 1118 "membership_type": int(membership_type), 1119 } 1120 response = await self._request( 1121 RequestMethod.POST, 1122 "Destiny2/Actions/Items/SetTrackedState", 1123 json=body, 1124 auth=access_token, 1125 ) 1126 assert isinstance(response, int) 1127 return response
Set the Tracking State for an instanced Quest or Bounty.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1129 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1130 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1131 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1132 assert isinstance(path, dict) 1133 return path
Fetch the manifest JSON paths.
Returns
typedefs.JSONObject: The manifest JSON paths.
1135 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1136 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1137 _ensure_manifest_language(language) 1138 1139 content = await self.fetch_manifest_path() 1140 resp = await self._request( 1141 RequestMethod.GET, 1142 content["mobileWorldContentPaths"][language], 1143 unwrapping="read", 1144 base=True, 1145 ) 1146 assert isinstance(resp, bytes) 1147 return resp
Read raw manifest SQLite database bytes response.
This method can be used to write the bytes to zipped file and then extract it to get the manifest content.
Parameters
- language (
str): The manifest database language bytes to get.
Returns
bytes: The bytes to read and write the manifest database.
1149 async def download_manifest( 1150 self, 1151 language: str = "en", 1152 name: str = "manifest.sqlite3", 1153 *, 1154 force: bool = False, 1155 ) -> None: 1156 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1157 if os.path.exists(name): 1158 1159 if force: 1160 _LOG.debug("Forcing manifest download.") 1161 os.remove(name) 1162 1163 return await self.download_manifest(language, name, force=force) 1164 1165 else: 1166 raise FileExistsError( 1167 "Manifest file already exists, " 1168 "If you want to force download, set the `force` parameter to `True`." 1169 ) 1170 1171 _LOG.debug("Downloading manifest...") 1172 data_bytes = await self.read_manifest_bytes(language) 1173 await asyncio.get_running_loop().run_in_executor( 1174 None, _write_sqlite_bytes, data_bytes, name 1175 )
A helper method to download the manifest.
Note
This method downloads the sqlite database and not JSON.
Use RESTInterface.download_json_manifest for the JSON version.
Parameters
- language (
str): The manifest language to download, Default is english. - name (
str): The manifest database file name. Default ismanifest.sqlite3 - force (
bool): Whether to force the download. Default isFalse. However if set to true the old file will get removed and a new one will being to download.
Returns
None
1177 async def download_json_manifest(self, language: str = "en") -> None: 1178 _ensure_manifest_language(language) 1179 1180 _LOG.debug("Downloading manifest JSON...") 1181 1182 content = await self.fetch_manifest_path() 1183 json_bytes = await self._request( 1184 RequestMethod.GET, 1185 content["jsonWorldContentPaths"][language], 1186 unwrapping="read", 1187 base=True, 1188 ) 1189 1190 await asyncio.get_running_loop().run_in_executor( 1191 None, _write_json_bytes, json_bytes 1192 ) 1193 _LOG.debug("Finished downloading manifest JSON.")
Download the Bungie manifest json file.
Parameters
- language (
str): The language to download the manifest in.
1195 async def fetch_manifest_version(self) -> str: 1196 return typing.cast(str, (await self.fetch_manifest_path())["version"])
Fetch the manifest version.
Returns
str: The manifest version.
1198 @staticmethod 1199 @helpers.deprecated( 1200 since="0.2.6a1", removed_in="0.2.6", use_instead="sqlite3.connect" 1201 ) 1202 def connect_manifest( 1203 path: typing.Optional[pathlib.Path] = None, 1204 connection: type[sqlite3.Connection] = sqlite3.Connection, 1205 ) -> sqlite3.Connection: 1206 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1207 path = path or pathlib.Path("./manifest.sqlite3") 1208 if not path.exists(): 1209 raise FileNotFoundError(f"Manifest in path {path.name} doesn't exists.") 1210 return connection(path.name)
A helper method to connect to the manifest database.
Parameters
- path (
typing.Optional[pathlib.Path]): An optional path to pass, The assumed path to connect to is './manifest.sqlite3' - connection (
type[sqlite3.Connection]): An optional connection to pass, if not passed a new connection will be created.
Returns
sqlite3.Connection: An SQLite database connection.
1212 async def fetch_linked_profiles( 1213 self, 1214 member_id: int, 1215 member_type: typedefs.IntAnd[enums.MembershipType], 1216 /, 1217 *, 1218 all: bool = False, 1219 ) -> typedefs.JSONObject: 1220 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1221 resp = await self._request( 1222 RequestMethod.GET, 1223 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1224 ) 1225 assert isinstance(resp, dict) 1226 return resp
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether thry're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.typedefs.JSONObject- A JSON object which contains an Array of profiles, an Array of profiles with errors and Bungie.Net membership
1236 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1237 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1238 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1239 assert isinstance(resp, dict) 1240 return resp
Fetch the available milestones.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information about the milestones.
1242 async def fetch_public_milestone_content( 1243 self, milestone_hash: int, / 1244 ) -> typedefs.JSONObject: 1245 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1246 resp = await self._request( 1247 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1248 ) 1249 assert isinstance(resp, dict) 1250 return resp
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information related to the fetched milestone.
1252 async def fetch_current_user_memberships( 1253 self, access_token: str, / 1254 ) -> typedefs.JSONObject: 1255 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1256 resp = await self._request( 1257 RequestMethod.GET, 1258 "User/GetMembershipsForCurrentUser/", 1259 auth=access_token, 1260 ) 1261 assert isinstance(resp, dict) 1262 return resp
Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.
This requires OAuth2 scope enabled and the valid Bearer access_token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the bungie net user and destiny memberships of this account.
1264 async def equip_item( 1265 self, 1266 access_token: str, 1267 /, 1268 item_id: int, 1269 character_id: int, 1270 membership_type: typedefs.IntAnd[enums.MembershipType], 1271 ) -> None: 1272 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1273 payload = { 1274 "itemId": item_id, 1275 "characterId": character_id, 1276 "membershipType": int(membership_type), 1277 } 1278 1279 await self._request( 1280 RequestMethod.POST, 1281 "Destiny2/Actions/Items/EquipItem/", 1282 json=payload, 1283 auth=access_token, 1284 )
Equip an item to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item id. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
1286 async def equip_items( 1287 self, 1288 access_token: str, 1289 /, 1290 item_ids: list[int], 1291 character_id: int, 1292 membership_type: typedefs.IntAnd[enums.MembershipType], 1293 ) -> None: 1294 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1295 payload = { 1296 "itemIds": item_ids, 1297 "characterId": character_id, 1298 "membershipType": int(membership_type), 1299 } 1300 await self._request( 1301 RequestMethod.POST, 1302 "Destiny2/Actions/Items/EquipItems/", 1303 json=payload, 1304 auth=access_token, 1305 )
Equip multiple items to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_ids (
list[int]): A list of item ids. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
1307 async def ban_clan_member( 1308 self, 1309 access_token: str, 1310 /, 1311 group_id: int, 1312 membership_id: int, 1313 membership_type: typedefs.IntAnd[enums.MembershipType], 1314 *, 1315 length: int = 0, 1316 comment: undefined.UndefinedOr[str] = undefined.Undefined, 1317 ) -> None: 1318 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1319 payload = {"comment": str(comment), "length": length} 1320 await self._request( 1321 RequestMethod.POST, 1322 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1323 json=payload, 1324 auth=access_token, 1325 )
Bans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to ban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- length (
int): An optional ban length. - comment (
aiobungie.UndefinedOr[str]): An optional comment to this ban. Default isUNDEFINED
1327 async def unban_clan_member( 1328 self, 1329 access_token: str, 1330 /, 1331 group_id: int, 1332 membership_id: int, 1333 membership_type: typedefs.IntAnd[enums.MembershipType], 1334 ) -> None: 1335 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1336 await self._request( 1337 RequestMethod.POST, 1338 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1339 auth=access_token, 1340 )
Unbans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to unban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
1342 async def kick_clan_member( 1343 self, 1344 access_token: str, 1345 /, 1346 group_id: int, 1347 membership_id: int, 1348 membership_type: typedefs.IntAnd[enums.MembershipType], 1349 ) -> typedefs.JSONObject: 1350 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1351 resp = await self._request( 1352 RequestMethod.POST, 1353 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1354 auth=access_token, 1355 ) 1356 assert isinstance(resp, dict) 1357 return resp
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the group that the member has been kicked from.
1359 async def edit_clan( 1360 self, 1361 access_token: str, 1362 /, 1363 group_id: int, 1364 *, 1365 name: typedefs.NoneOr[str] = None, 1366 about: typedefs.NoneOr[str] = None, 1367 motto: typedefs.NoneOr[str] = None, 1368 theme: typedefs.NoneOr[str] = None, 1369 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1370 is_public: typedefs.NoneOr[bool] = None, 1371 locale: typedefs.NoneOr[str] = None, 1372 avatar_image_index: typedefs.NoneOr[int] = None, 1373 membership_option: typedefs.NoneOr[ 1374 typedefs.IntAnd[enums.MembershipOption] 1375 ] = None, 1376 allow_chat: typedefs.NoneOr[bool] = None, 1377 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1378 call_sign: typedefs.NoneOr[str] = None, 1379 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1380 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1381 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1382 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1383 ) -> None: 1384 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1385 payload = { 1386 "name": name, 1387 "about": about, 1388 "motto": motto, 1389 "theme": theme, 1390 "tags": tags, 1391 "isPublic": is_public, 1392 "avatarImageIndex": avatar_image_index, 1393 "isPublicTopicAdminOnly": is_public_topic_admin, 1394 "allowChat": allow_chat, 1395 "chatSecurity": chat_security, 1396 "callsign": call_sign, 1397 "homepage": homepage, 1398 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1399 "defaultPublicity": default_publicity, 1400 "locale": locale, 1401 } 1402 if membership_option is not None: 1403 payload["membershipOption"] = int(membership_option) 1404 1405 await self._request( 1406 RequestMethod.POST, 1407 f"GroupV2/{group_id}/Edit", 1408 json=payload, 1409 auth=access_token, 1410 )
Edit a clan.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id to edit.
Other Parameters
- name (
aiobungie.typedefs.NoneOr[str]): The name to edit the clan with. - about (
aiobungie.typedefs.NoneOr[str]): The about section to edit the clan with. - motto (
aiobungie.typedefs.NoneOr[str]): The motto section to edit the clan with. - theme (
aiobungie.typedefs.NoneOr[str]): The theme name to edit the clan with. - tags (
aiobungie.typedefs.NoneOr[collections.Sequence[str]]): A sequence of strings to replace the clan tags with. - is_public (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan will set to private. If provided and set toFalse, The clan will set to public whether it was or not. - locale (
aiobungie.typedefs.NoneOr[str]): The locale section to edit the clan with. - avatar_image_index (
aiobungie.typedefs.NoneOr[int]): The clan avatar image index to edit the clan with. - membership_option :
aiobungie.typedefs.NoneOr[aiobungie.typedefs.IntAnd[aiobungie.MembershipOption]]# noqa (E501 # Line too long): The clan membership option to edit it with. - allow_chat (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan members will be allowed to chat. If provided and set toFalse, The clan members will not be allowed to chat. - chat_security (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1]]): If provided and set to0, The clan chat security will be edited toGrouponly. If provided and set to1, The clan chat security will be edited toAdminonly. - call_sign (
aiobungie.typedefs.NoneOr[str]): The clan call sign to edit it with. - homepage (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat homepage will be edited toWall. If provided and set to1, The clan chat homepage will be edited toForum. If provided and set to0, The clan chat homepage will be edited toAllianceForum. - enable_invite_messaging_for_admins (
aiobungie.typedefs.NoneOr[bool]): ??? - default_publicity (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat publicity will be edited toPublic. If provided and set to1, The clan chat publicity will be edited toAlliance. If provided and set to2, The clan chat publicity will be edited toPrivate. - is_public_topic_admin (
aiobungie.typedefs.NoneOr[bool]): ???
1412 async def edit_clan_options( 1413 self, 1414 access_token: str, 1415 /, 1416 group_id: int, 1417 *, 1418 invite_permissions_override: typedefs.NoneOr[bool] = None, 1419 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1420 host_guided_game_permission_override: typedefs.NoneOr[ 1421 typing.Literal[0, 1, 2] 1422 ] = None, 1423 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1424 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1425 ) -> None: 1426 1427 payload = { 1428 "InvitePermissionOverride": invite_permissions_override, 1429 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1430 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1431 "UpdateBannerPermissionOverride": update_banner_permission_override, 1432 "JoinLevel": int(join_level) if join_level else None, 1433 } 1434 1435 await self._request( 1436 RequestMethod.POST, 1437 f"GroupV2/{group_id}/EditFounderOptions", 1438 json=payload, 1439 auth=access_token, 1440 )
Edit the clan options.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id.
Other Parameters
- invite_permissions_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - update_culture_permissionOverride (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - host_guided_game_permission_override (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides:0-> None,1-> Beginner2-> Member. Default is Member for clans, None for groups, although this means nothing for groups. - update_banner_permission_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - join_level (
aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default isaiobungie.ClanMemberType.BEGINNER
1442 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1443 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1444 resp = await self._request( 1445 RequestMethod.GET, 1446 "Social/Friends/", 1447 auth=access_token, 1448 ) 1449 assert isinstance(resp, dict) 1450 return resp
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the bungie friends's data.
1452 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1453 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1454 resp = await self._request( 1455 RequestMethod.GET, 1456 "Social/Friends/Requests", 1457 auth=access_token, 1458 ) 1459 assert isinstance(resp, dict) 1460 return resp
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of incoming requests and outgoing requests.
1462 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1463 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1464 await self._request( 1465 RequestMethod.POST, 1466 f"Social/Friends/Requests/Accept/{member_id}", 1467 auth=access_token, 1468 )
Accepts a friend relationship with the target user. The user must be on your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to accept.
1470 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1471 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1472 await self._request( 1473 RequestMethod.POST, 1474 f"Social/Friends/Add/{member_id}", 1475 auth=access_token, 1476 )
Requests a friend relationship with the target user.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to send the request to.
1478 async def decline_friend_request( 1479 self, access_token: str, /, member_id: int 1480 ) -> None: 1481 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1482 await self._request( 1483 RequestMethod.POST, 1484 f"Social/Friends/Requests/Decline/{member_id}", 1485 auth=access_token, 1486 )
Decline a friend request with the target user. The user must be in your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to decline.
1488 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1489 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1490 await self._request( 1491 RequestMethod.POST, 1492 f"Social/Friends/Remove/{member_id}", 1493 auth=access_token, 1494 )
Removes a friend from your friend list. The user must be in your friend list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove.
1496 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1497 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1498 await self._request( 1499 RequestMethod.POST, 1500 f"Social/Friends/Requests/Remove/{member_id}", 1501 auth=access_token, 1502 )
Removes a friend from your friend list requests. The user must be in your outgoing request list.
.. note : This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove from the requested friend list.
1504 async def approve_all_pending_group_users( 1505 self, 1506 access_token: str, 1507 /, 1508 group_id: int, 1509 message: undefined.UndefinedOr[str] = undefined.Undefined, 1510 ) -> None: 1511 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1512 await self._request( 1513 RequestMethod.POST, 1514 f"GroupV2/{group_id}/Members/ApproveAll", 1515 auth=access_token, 1516 json={"message": str(message)}, 1517 )
Apporve all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1519 async def deny_all_pending_group_users( 1520 self, 1521 access_token: str, 1522 /, 1523 group_id: int, 1524 *, 1525 message: undefined.UndefinedOr[str] = undefined.Undefined, 1526 ) -> None: 1527 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1528 await self._request( 1529 RequestMethod.POST, 1530 f"GroupV2/{group_id}/Members/DenyAll", 1531 auth=access_token, 1532 json={"message": str(message)}, 1533 )
Deny all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1535 async def add_optional_conversation( 1536 self, 1537 access_token: str, 1538 /, 1539 group_id: int, 1540 *, 1541 name: undefined.UndefinedOr[str] = undefined.Undefined, 1542 security: typing.Literal[0, 1] = 0, 1543 ) -> None: 1544 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1545 payload = {"chatName": str(name), "chatSecurity": security} 1546 await self._request( 1547 RequestMethod.POST, 1548 f"GroupV2/{group_id}/OptionalConversations/Add", 1549 json=payload, 1550 auth=access_token, 1551 )
Add a new chat channel to a group.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other parameters
name: aiobungie.UndefinedOr[str]
The chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
1553 async def edit_optional_conversation( 1554 self, 1555 access_token: str, 1556 /, 1557 group_id: int, 1558 conversation_id: int, 1559 *, 1560 name: undefined.UndefinedOr[str] = undefined.Undefined, 1561 security: typing.Literal[0, 1] = 0, 1562 enable_chat: bool = False, 1563 ) -> None: 1564 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1565 payload = { 1566 "chatEnabled": enable_chat, 1567 "chatName": str(name), 1568 "chatSecurity": security, 1569 } 1570 await self._request( 1571 RequestMethod.POST, 1572 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1573 json=payload, 1574 auth=access_token, 1575 )
Edit the settings of this chat channel.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id. - conversation_id (
int): The conversation/chat id.
Other parameters
name: aiobungie.UndefinedOr[str]
The new chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The new security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
enable_chat : bool
Whether to enable chatting or not.
If set to True then chatting will be enabled. Otherwise it will be disabled.
1577 async def transfer_item( 1578 self, 1579 access_token: str, 1580 /, 1581 item_id: int, 1582 item_hash: int, 1583 character_id: int, 1584 member_type: typedefs.IntAnd[enums.MembershipType], 1585 *, 1586 stack_size: int = 1, 1587 vault: bool = False, 1588 ) -> None: 1589 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1590 payload = { 1591 "characterId": character_id, 1592 "membershipType": int(member_type), 1593 "itemId": item_id, 1594 "itemReferenceHash": item_hash, 1595 "stackSize": stack_size, 1596 "transferToVault": vault, 1597 } 1598 await self._request( 1599 RequestMethod.POST, 1600 "Destiny2/Actions/Items/TransferItem", 1601 json=payload, 1602 auth=access_token, 1603 )
Transfer an item from / to your vault.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id you to transfer. - item_hash (
int): The item hash. - character_id (
int): The character id to transfer the item from/to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - valut (
bool): Whether to trasnfer this item to your valut or not. Defaults toFalse.
1605 async def pull_item( 1606 self, 1607 access_token: str, 1608 /, 1609 item_id: int, 1610 item_hash: int, 1611 character_id: int, 1612 member_type: typedefs.IntAnd[enums.MembershipType], 1613 *, 1614 stack_size: int = 1, 1615 vault: bool = False, 1616 ) -> None: 1617 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1618 payload = { 1619 "characterId": character_id, 1620 "membershipType": int(member_type), 1621 "itemId": item_id, 1622 "itemReferenceHash": item_hash, 1623 "stackSize": stack_size, 1624 "transferToVault": vault, 1625 } 1626 await self._request( 1627 RequestMethod.POST, 1628 "Destiny2/Actions/Items/PullFromPostmaster", 1629 json=payload, 1630 auth=access_token, 1631 )
pull an item from the postmaster.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id to pull. - item_hash (
int): The item hash. - character_id (
int): The character id to pull the item to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - valut (
bool): Whether to pill this item to your valut or not. Defaults toFalse.
1633 async def fetch_fireteams( 1634 self, 1635 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1636 *, 1637 platform: typedefs.IntAnd[ 1638 fireteams.FireteamPlatform 1639 ] = fireteams.FireteamPlatform.ANY, 1640 language: typing.Union[ 1641 fireteams.FireteamLanguage, str 1642 ] = fireteams.FireteamLanguage.ALL, 1643 date_range: typedefs.IntAnd[ 1644 fireteams.FireteamDate 1645 ] = fireteams.FireteamDate.ALL, 1646 page: int = 0, 1647 slots_filter: int = 0, 1648 ) -> typedefs.JSONObject: 1649 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1650 resp = await self._request( 1651 RequestMethod.GET, 1652 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1653 ) 1654 assert isinstance(resp, dict) 1655 return resp
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1657 async def fetch_avaliable_clan_fireteams( 1658 self, 1659 access_token: str, 1660 group_id: int, 1661 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1662 *, 1663 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1664 language: typing.Union[fireteams.FireteamLanguage, str], 1665 date_range: typedefs.IntAnd[ 1666 fireteams.FireteamDate 1667 ] = fireteams.FireteamDate.ALL, 1668 page: int = 0, 1669 public_only: bool = False, 1670 slots_filter: int = 0, 1671 ) -> typedefs.JSONObject: 1672 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1673 resp = await self._request( 1674 RequestMethod.GET, 1675 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1676 json={"langFilter": str(language)}, 1677 auth=access_token, 1678 ) 1679 assert isinstance(resp, dict) 1680 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1682 async def fetch_clan_fireteam( 1683 self, access_token: str, fireteam_id: int, group_id: int 1684 ) -> typedefs.JSONObject: 1685 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1686 resp = await self._request( 1687 RequestMethod.GET, 1688 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1689 auth=access_token, 1690 ) 1691 assert isinstance(resp, dict) 1692 return resp
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1694 async def fetch_my_clan_fireteams( 1695 self, 1696 access_token: str, 1697 group_id: int, 1698 *, 1699 include_closed: bool = True, 1700 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1701 language: typing.Union[fireteams.FireteamLanguage, str], 1702 filtered: bool = True, 1703 page: int = 0, 1704 ) -> typedefs.JSONObject: 1705 payload = {"groupFilter": filtered, "langFilter": str(language)} 1706 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1707 resp = await self._request( 1708 RequestMethod.GET, 1709 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1710 json=payload, 1711 auth=access_token, 1712 ) 1713 assert isinstance(resp, dict) 1714 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch.
Other Parameters
- include_closed (
bool): If provided and set toTrue, It will also return closed fireteams. If provided and set toFalse, It will only return public fireteams. Default isTrue. - platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - filtered (
bool): If set toTrue, it will filter by clan. Otherwise not. Default isTrue. - page (
int): The page number. By default its0which returns all available activities.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1716 async def fetch_private_clan_fireteams( 1717 self, access_token: str, group_id: int, / 1718 ) -> int: 1719 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1720 resp = await self._request( 1721 RequestMethod.GET, 1722 f"Fireteam/Clan/{group_id}/ActiveCount", 1723 auth=access_token, 1724 ) 1725 assert isinstance(resp, int) 1726 return resp
Fetch the active count of the clan fireteams that are only private.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id.
Returns
int: The active fireteams count. Max value returned is 25.
1728 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1729 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1730 resp = await self._request( 1731 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1732 ) 1733 assert isinstance(resp, dict) 1734 return resp
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the post activity.
1736 async def search_entities( 1737 self, name: str, entity_type: str, *, page: int = 0 1738 ) -> typedefs.JSONObject: 1739 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1740 resp = await self._request( 1741 RequestMethod.GET, 1742 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1743 json={"page": page}, 1744 ) 1745 assert isinstance(resp, dict) 1746 return resp
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinition
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the searched term.
1748 async def fetch_unique_weapon_history( 1749 self, 1750 membership_id: int, 1751 character_id: int, 1752 membership_type: typedefs.IntAnd[enums.MembershipType], 1753 ) -> typedefs.JSONObject: 1754 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1755 resp = await self._request( 1756 RequestMethod.GET, 1757 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1758 ) 1759 assert isinstance(resp, dict) 1760 return resp
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the returned weapons.
1762 async def fetch_item( 1763 self, 1764 member_id: int, 1765 item_id: int, 1766 membership_type: typedefs.IntAnd[enums.MembershipType], 1767 components: list[enums.ComponentType], 1768 ) -> typedefs.JSONObject: 1769 collector = _collect_components(components) 1770 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1771 resp = await self._request( 1772 RequestMethod.GET, 1773 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1774 ) 1775 assert isinstance(resp, dict) 1776 return resp
Fetch an instanced Destiny 2 item's details.
Parameters
- member_id (
int): The membership id of the Destiny 2 player. - item_id (
int): The instance id of the item. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type of the Destiny 2 player. - components (
list[aiobungie.ComponentType]): A list of components to retrieve.
Returns
aiobungie.typedefs.JSONObject: A JSON object response contains the fetched item with its components.
1778 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1779 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1780 resp = await self._request( 1781 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1782 ) 1783 assert isinstance(resp, dict) 1784 return resp
Fetch the weekly reward state for a clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON response of the clan rewards state.
1786 async def fetch_available_locales(self) -> typedefs.JSONObject: 1787 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1788 resp = await self._request( 1789 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1790 ) 1791 assert isinstance(resp, dict) 1792 return resp
Fetch available locales at Bungie.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains a list of all available localization cultures.
1794 async def fetch_common_settings(self) -> typedefs.JSONObject: 1795 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1796 resp = await self._request(RequestMethod.GET, "Settings") 1797 assert isinstance(resp, dict) 1798 return resp
Fetch the common settings used by Bungie's envirotment.
Returns
aiobungie.typedefs.JSONObject: The common settings JSON object.
1800 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1801 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1802 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1803 assert isinstance(resp, dict) 1804 return resp
Fetch a user's specific system overrides.
Returns
aiobungie.typedefs.JSONObject: The system overrides JSON object.
1806 async def fetch_global_alerts( 1807 self, *, include_streaming: bool = False 1808 ) -> typedefs.JSONArray: 1809 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1810 resp = await self._request( 1811 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1812 ) 1813 assert isinstance(resp, list) 1814 return resp
Fetch any active global alerts.
Parameters
- include_streaming (
bool): If True, the returned results will include streaming alerts. Default is False.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the global alerts objects.
1816 async def awainitialize_request( 1817 self, 1818 access_token: str, 1819 type: typing.Literal[0, 1], 1820 membership_type: typedefs.IntAnd[enums.MembershipType], 1821 /, 1822 *, 1823 affected_item_id: typing.Optional[int] = None, 1824 character_id: typing.Optional[int] = None, 1825 ) -> typedefs.JSONObject: 1826 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1827 1828 body = {"type": type, "membershipType": int(membership_type)} 1829 1830 if affected_item_id is not None: 1831 body["affectedItemId"] = affected_item_id 1832 1833 if character_id is not None: 1834 body["characterId"] = character_id 1835 1836 resp = await self._request( 1837 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1838 ) 1839 assert isinstance(resp, dict) 1840 return resp
Initialize a request to perform an advanced write action.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - type (
typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means itNone. Otherwise if 1 that means its insert plugs. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
- affected_item_id (
typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values. - character_id (
typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1842 async def awaget_action_token( 1843 self, access_token: str, correlation_id: str, / 1844 ) -> typedefs.JSONObject: 1845 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1846 resp = await self._request( 1847 RequestMethod.POST, 1848 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1849 auth=access_token, 1850 ) 1851 assert isinstance(resp, dict) 1852 return resp
Returns the action token if user approves the request.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - correlation_id (
str): The identifier for the advanced write action request.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1874 async def fetch_vendors( 1875 self, 1876 access_token: str, 1877 character_id: int, 1878 membership_id: int, 1879 membership_type: typedefs.IntAnd[enums.MembershipType], 1880 /, 1881 components: list[enums.ComponentType], 1882 filter: typing.Optional[int] = None, 1883 ) -> typedefs.JSONObject: 1884 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1885 components_ = _collect_components(components) 1886 route = ( 1887 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1888 f"/Character/{character_id}/Vendors/?components={components_}" 1889 ) 1890 1891 if filter is not None: 1892 route = route + f"&filter={filter}" 1893 1894 resp = await self._request( 1895 RequestMethod.GET, 1896 route, 1897 auth=access_token, 1898 ) 1899 assert isinstance(resp, dict) 1900 return resp
Get currently available vendors from the list of vendors that can possibly have rotating inventory.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
- filter (
int): Filters the type of items returned from the vendor. This can be left toNone.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1902 async def fetch_vendor( 1903 self, 1904 access_token: str, 1905 character_id: int, 1906 membership_id: int, 1907 membership_type: typedefs.IntAnd[enums.MembershipType], 1908 vendor_hash: int, 1909 /, 1910 components: list[enums.ComponentType], 1911 ) -> typedefs.JSONObject: 1912 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1913 components_ = _collect_components(components) 1914 resp = await self._request( 1915 RequestMethod.GET, 1916 ( 1917 f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}" 1918 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1919 ), 1920 auth=access_token, 1921 ) 1922 assert isinstance(resp, dict) 1923 return resp
Fetch details for a specific vendor.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - vendor_hash (
int): The vendor hash to return the details for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1925 async def fetch_application_api_usage( 1926 self, 1927 access_token: str, 1928 application_id: int, 1929 /, 1930 *, 1931 start: typing.Optional[datetime.datetime] = None, 1932 end: typing.Optional[datetime.datetime] = None, 1933 ) -> typedefs.JSONObject: 1934 1935 end_date, start_date = time.parse_date_range(end, start) 1936 resp = await self._request( 1937 RequestMethod.GET, 1938 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1939 auth=access_token, 1940 ) 1941 assert isinstance(resp, dict) 1942 return resp
Fetch a Bungie application's API usage.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - application_id (
int): The application id to get.
Other Parameters
start (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.If this is left to
None. It will return the last 24 hours.end (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.If this is left to
None. It will returnnow.
Example
import datetime
# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application usage details.
1944 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1945 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1946 assert isinstance(resp, list) 1947 return resp
Fetch details for applications created by Bungie.
Returns
aiobungie.typedefs.JSONArray: An array of Bungie created applications.
1954 async def fetch_content_by_id( 1955 self, id: int, locale: str, /, *, head: bool = False 1956 ) -> typedefs.JSONObject: 1957 resp = await self._request( 1958 RequestMethod.GET, 1959 f"Content/GetContentById/{id}/{locale}/", 1960 json={"head": head}, 1961 ) 1962 assert isinstance(resp, dict) 1963 return resp
1965 async def fetch_content_by_tag_and_type( 1966 self, locale: str, tag: str, type: str, *, head: bool = False 1967 ) -> typedefs.JSONObject: 1968 resp = await self._request( 1969 RequestMethod.GET, 1970 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1971 json={"head": head}, 1972 ) 1973 assert isinstance(resp, dict) 1974 return resp
1976 async def search_content_with_text( 1977 self, 1978 locale: str, 1979 /, 1980 content_type: str, 1981 search_text: str, 1982 tag: str, 1983 *, 1984 page: undefined.UndefinedOr[int] = undefined.Undefined, 1985 source: undefined.UndefinedOr[str] = undefined.Undefined, 1986 ) -> typedefs.JSONObject: 1987 1988 body: typedefs.JSONObject = {} 1989 1990 body["ctype"] = content_type 1991 body["searchtext"] = search_text 1992 body["tag"] = tag 1993 1994 if page is not undefined.Undefined: 1995 body["currentpage"] = page 1996 else: 1997 body["currentpage"] = 1 1998 1999 if source is not undefined.Undefined: 2000 body["source"] = source 2001 else: 2002 source = "" 2003 resp = await self._request( 2004 RequestMethod.GET, f"Content/Search/{locale}/", json=body 2005 ) 2006 assert isinstance(resp, dict) 2007 return resp
2009 async def search_content_by_tag_and_type( 2010 self, 2011 locale: str, 2012 tag: str, 2013 type: str, 2014 *, 2015 page: undefined.UndefinedOr[int] = undefined.Undefined, 2016 ) -> typedefs.JSONObject: 2017 body: typedefs.JSONObject = {} 2018 body["currentpage"] = 1 if page is undefined.Undefined else page 2019 resp = await self._request( 2020 RequestMethod.GET, 2021 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 2022 json=body, 2023 ) 2024 assert isinstance(resp, dict) 2025 return resp
2036 async def fetch_topics_page( 2037 self, 2038 category_filter: int, 2039 group: int, 2040 date_filter: int, 2041 sort: typing.Union[str, bytes], 2042 *, 2043 page: undefined.UndefinedOr[int] = undefined.Undefined, 2044 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2045 tag_filter: undefined.UndefinedOr[str] = undefined.Undefined, 2046 ) -> typedefs.JSONObject: 2047 2048 body: typedefs.JSONObject = {} 2049 if locales is not undefined.Undefined: 2050 body["locales"] = ",".join(str(locales)) 2051 else: 2052 body["locales"] = ",".join([]) 2053 2054 if tag_filter is not undefined.Undefined: 2055 body["tagstring"] = tag_filter 2056 else: 2057 body["tagstring"] = "" 2058 2059 page = 0 if page is not undefined.Undefined else page 2060 2061 resp = await self._request( 2062 RequestMethod.GET, 2063 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 2064 json=body, 2065 ) 2066 assert isinstance(resp, dict) 2067 return resp
2069 async def fetch_core_topics_page( 2070 self, 2071 category_filter: int, 2072 date_filter: int, 2073 sort: typing.Union[str, bytes], 2074 *, 2075 page: undefined.UndefinedOr[int] = undefined.Undefined, 2076 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2077 ) -> typedefs.JSONObject: 2078 body: typedefs.JSONObject = {} 2079 2080 if locales is not undefined.Undefined: 2081 body["locales"] = ",".join(str(locales)) 2082 else: 2083 body["locales"] = ",".join([]) 2084 2085 resp = await self._request( 2086 RequestMethod.GET, 2087 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}" 2088 f"/{sort!s}/{date_filter}/{category_filter}/", 2089 json=body, 2090 ) 2091 assert isinstance(resp, dict) 2092 return resp
2094 async def fetch_posts_threaded_page( 2095 self, 2096 parent_post: bool, 2097 page: int, 2098 page_size: int, 2099 parent_post_id: int, 2100 reply_size: int, 2101 root_thread_mode: bool, 2102 sort_mode: int, 2103 show_banned: typing.Optional[str] = None, 2104 ) -> typedefs.JSONObject: 2105 resp = await self._request( 2106 RequestMethod.GET, 2107 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 2108 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 2109 json={"showbanned": show_banned}, 2110 ) 2111 assert isinstance(resp, dict) 2112 return resp
2114 async def fetch_posts_threaded_page_from_child( 2115 self, 2116 child_id: bool, 2117 page: int, 2118 page_size: int, 2119 reply_size: int, 2120 root_thread_mode: bool, 2121 sort_mode: int, 2122 show_banned: typing.Optional[str] = None, 2123 ) -> typedefs.JSONObject: 2124 resp = await self._request( 2125 RequestMethod.GET, 2126 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 2127 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 2128 json={"showbanned": show_banned}, 2129 ) 2130 assert isinstance(resp, dict) 2131 return resp
2133 async def fetch_post_and_parent( 2134 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2135 ) -> typedefs.JSONObject: 2136 resp = await self._request( 2137 RequestMethod.GET, 2138 f"Forum/GetPostAndParent/{child_id}/", 2139 json={"showbanned": show_banned}, 2140 ) 2141 assert isinstance(resp, dict) 2142 return resp
2144 async def fetch_posts_and_parent_awaiting( 2145 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2146 ) -> typedefs.JSONObject: 2147 resp = await self._request( 2148 RequestMethod.GET, 2149 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2150 json={"showbanned": show_banned}, 2151 ) 2152 assert isinstance(resp, dict) 2153 return resp
2183 async def fetch_recommended_groups( 2184 self, 2185 accecss_token: str, 2186 /, 2187 *, 2188 date_range: int = 0, 2189 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2190 ) -> typedefs.JSONArray: 2191 resp = await self._request( 2192 RequestMethod.POST, 2193 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2194 auth=accecss_token, 2195 ) 2196 assert isinstance(resp, list) 2197 return resp
2204 async def fetch_user_clan_invite_setting( 2205 self, 2206 access_token: str, 2207 /, 2208 membership_type: typedefs.IntAnd[enums.MembershipType], 2209 ) -> bool: 2210 resp = await self._request( 2211 RequestMethod.GET, 2212 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2213 auth=access_token, 2214 ) 2215 assert isinstance(resp, bool) 2216 return resp
2218 async def fetch_banned_group_members( 2219 self, access_token: str, group_id: int, /, *, page: int = 1 2220 ) -> typedefs.JSONObject: 2221 resp = await self._request( 2222 RequestMethod.GET, 2223 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2224 auth=access_token, 2225 ) 2226 assert isinstance(resp, dict) 2227 return resp
2229 async def fetch_pending_group_memberships( 2230 self, access_token: str, group_id: int, /, *, current_page: int = 1 2231 ) -> typedefs.JSONObject: 2232 resp = await self._request( 2233 RequestMethod.GET, 2234 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2235 auth=access_token, 2236 ) 2237 assert isinstance(resp, dict) 2238 return resp
2240 async def fetch_invited_group_memberships( 2241 self, access_token: str, group_id: int, /, *, current_page: int = 1 2242 ) -> typedefs.JSONObject: 2243 resp = await self._request( 2244 RequestMethod.GET, 2245 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2246 auth=access_token, 2247 ) 2248 assert isinstance(resp, dict) 2249 return resp
2251 async def invite_member_to_group( 2252 self, 2253 access_token: str, 2254 /, 2255 group_id: int, 2256 membership_id: int, 2257 membership_type: typedefs.IntAnd[enums.MembershipType], 2258 *, 2259 message: undefined.UndefinedOr[str] = undefined.Undefined, 2260 ) -> typedefs.JSONObject: 2261 resp = await self._request( 2262 RequestMethod.POST, 2263 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2264 auth=access_token, 2265 json={"message": str(message)}, 2266 ) 2267 assert isinstance(resp, dict) 2268 return resp
2270 async def cancel_group_member_invite( 2271 self, 2272 access_token: str, 2273 /, 2274 group_id: int, 2275 membership_id: int, 2276 membership_type: typedefs.IntAnd[enums.MembershipType], 2277 ) -> typedefs.JSONObject: 2278 resp = await self._request( 2279 RequestMethod.POST, 2280 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2281 auth=access_token, 2282 ) 2283 assert isinstance(resp, dict) 2284 return resp
2291 async def fetch_historical_stats( 2292 self, 2293 character_id: int, 2294 membership_id: int, 2295 membership_type: typedefs.IntAnd[enums.MembershipType], 2296 day_start: datetime.datetime, 2297 day_end: datetime.datetime, 2298 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2299 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2300 *, 2301 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2302 ) -> typedefs.JSONObject: 2303 2304 end, start = time.parse_date_range(day_end, day_start) 2305 resp = await self._request( 2306 RequestMethod.GET, 2307 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2308 json={ 2309 "dayend": end, 2310 "daystart": start, 2311 "groups": [str(int(group)) for group in groups], 2312 "modes": [str(int(mode)) for mode in modes], 2313 "periodType": int(period_type), 2314 }, 2315 ) 2316 assert isinstance(resp, dict) 2317 return resp
Fetch historical stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - day_start (
datetime.datetime): The start of the day to return the stats for. - day_end (
datetime.datetime): The end of the day to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return. - modes (
list[aiobungie.GameMode | int]): A list of game modes to return. - period_type (
aiobungie.enums.PeriodType): The period type to return the stats for. This will returnALL_TIMEby default if not modified.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats.
2319 async def fetch_historical_stats_for_account( 2320 self, 2321 membership_id: int, 2322 membership_type: typedefs.IntAnd[enums.MembershipType], 2323 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2324 ) -> typedefs.JSONObject: 2325 resp = await self._request( 2326 RequestMethod.GET, 2327 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2328 json={"groups": [str(int(group)) for group in groups]}, 2329 ) 2330 assert isinstance(resp, dict) 2331 return resp
Fetch historical stats for an account's membership.
Parameters
- membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats for the account. This includes both the character and account stats.
2333 async def fetch_aggregated_activity_stats( 2334 self, 2335 character_id: int, 2336 membership_id: int, 2337 membership_type: typedefs.IntAnd[enums.MembershipType], 2338 /, 2339 ) -> typedefs.JSONObject: 2340 resp = await self._request( 2341 RequestMethod.GET, 2342 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2343 f"Character/{character_id}/Stats/AggregateActivityStats/", 2344 ) 2345 assert isinstance(resp, dict) 2346 return resp
Fetch aggregated activity stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the aggregated activity stats.
234class RESTPool: 235 """Pool of `RESTClient` instances. 236 237 This allows to create multiple instances of `RESTClient`s that can be acquired 238 which share the same connector and metadata. 239 240 Example 241 ------- 242 ```py 243 import aiobungie 244 245 client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret') 246 247 # Using a context manager to acquire an instance 248 # of the pool and close the connection after finishing. 249 250 async with client_pool.acquire() as client: 251 await client.download_manifest() 252 return client.build_oauth2_url() 253 254 async with client_pool.acquire() as client: 255 new_tokens = await client.refresh_access_token("token") 256 # Tokens now can be used from any pool. 257 client.metadata['tokens'] = new_tokens 258 ``` 259 260 Parameters 261 ---------- 262 token : `str` 263 A valid application token from Bungie's developer portal. 264 265 Other Parameters 266 ---------------- 267 max_retries : `int` 268 The max retries number to retry if the request hit a `5xx` status code. 269 max_ratelimit_retries : `int` 270 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 271 client_secret : `typing.Optional[str]` 272 An optional application client secret, 273 This is only needed if you're fetching OAuth2 tokens with this client. 274 client_id : `typing.Optional[int]` 275 An optional application client id, 276 This is only needed if you're fetching OAuth2 tokens with this client. 277 enable_debugging : `bool | str` 278 Whether to enable logging responses or not. 279 280 Logging Levels 281 -------------- 282 * `False`: This will disable logging. 283 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 284 Like the response status, route, taken time and so on. 285 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 286 """ 287 288 __slots__ = ( 289 "_token", 290 "_max_retries", 291 "_client_secret", 292 "_client_id", 293 "_max_rate_limit_retries", 294 "_metadata", 295 "_enable_debug", 296 ) 297 298 # Looks like mypy doesn't like this. 299 if typing.TYPE_CHECKING: 300 _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int] 301 302 def __init__( 303 self, 304 token: str, 305 /, 306 client_secret: typing.Optional[str] = None, 307 client_id: typing.Optional[int] = None, 308 *, 309 max_retries: int = 4, 310 max_rate_limit_retries: int = 3, 311 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 312 ) -> None: 313 self._client_secret = client_secret 314 self._client_id = client_id 315 self._token: str = token 316 self._max_retries = max_retries 317 self._max_rate_limit_retries = max_rate_limit_retries 318 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 319 self._enable_debug = enable_debugging 320 321 @property 322 def client_id(self) -> typing.Optional[int]: 323 return self._client_id 324 325 @property 326 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 327 """Pool's Metadata. This is different from client instance metadata.""" 328 return self._metadata 329 330 @typing.final 331 def acquire(self) -> RESTClient: 332 """Acquires a new `RESTClient` instance from this REST pool. 333 334 Returns 335 ------- 336 `RESTClient` 337 An instance of a REST client. 338 """ 339 instance = RESTClient( 340 self._token, 341 client_secret=self._client_secret, 342 client_id=self._client_id, 343 max_retries=self._max_retries, 344 max_ratelimit_retries=self._max_rate_limit_retries, 345 enable_debugging=self._enable_debug, 346 ) 347 return instance
Pool of RESTClient instances.
This allows to create multiple instances of RESTClients that can be acquired
which share the same connector and metadata.
Example
import aiobungie
client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.
async with client_pool.acquire() as client:
await client.download_manifest()
return client.build_oauth2_url()
async with client_pool.acquire() as client:
new_tokens = await client.refresh_access_token("token")
# Tokens now can be used from any pool.
client.metadata['tokens'] = new_tokens
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information. Like the response status, route, taken time and so on."TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
302 def __init__( 303 self, 304 token: str, 305 /, 306 client_secret: typing.Optional[str] = None, 307 client_id: typing.Optional[int] = None, 308 *, 309 max_retries: int = 4, 310 max_rate_limit_retries: int = 3, 311 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 312 ) -> None: 313 self._client_secret = client_secret 314 self._client_id = client_id 315 self._token: str = token 316 self._max_retries = max_retries 317 self._max_rate_limit_retries = max_rate_limit_retries 318 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 319 self._enable_debug = enable_debugging
Pool's Metadata. This is different from client instance metadata.
330 @typing.final 331 def acquire(self) -> RESTClient: 332 """Acquires a new `RESTClient` instance from this REST pool. 333 334 Returns 335 ------- 336 `RESTClient` 337 An instance of a REST client. 338 """ 339 instance = RESTClient( 340 self._token, 341 client_secret=self._client_secret, 342 client_id=self._client_id, 343 max_retries=self._max_retries, 344 max_ratelimit_retries=self._max_rate_limit_retries, 345 enable_debugging=self._enable_debug, 346 ) 347 return instance
Acquires a new RESTClient instance from this REST pool.
Returns
RESTClient: An instance of a REST client.
496@typing.final 497class Race(int, Enum): 498 """An Enum for Destiny races.""" 499 500 HUMAN = 0 501 AWOKEN = 1 502 EXO = 2 503 UNKNOWN = 3
An Enum for Destiny races.
148@typing.final 149class Raid(int, Enum): 150 """An Enum for all available raids in Destiny 2.""" 151 152 DSC = 910380154 153 """Deep Stone Crypt""" 154 155 LW = 2122313384 156 """Last Wish""" 157 158 VOG = 3881495763 159 """Normal Valut of Glass""" 160 161 GOS = 3458480158 162 """Garden Of Salvation"""
An Enum for all available raids in Destiny 2.
213@attrs.define(auto_exc=True) 214class RateLimitedError(HTTPError): 215 """Raised when being hit with ratelimits.""" 216 217 http_status: http.HTTPStatus = attrs.field( 218 default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False 219 ) 220 """The request response http status.""" 221 222 url: typedefs.StrOrURL 223 """The URL/endpoint caused this error.""" 224 225 body: typing.Any 226 """The response body.""" 227 228 retry_after: float = attrs.field(default=0.0) 229 """The amount of seconds you need to wait before retrying to requests.""" 230 231 message: str = attrs.field(init=False) 232 """A Bungie human readable message describes the cause of the error.""" 233 234 @message.default # type: ignore 235 def _(self) -> str: 236 return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!" 237 238 def __str__(self) -> str: 239 return self.message
Raised when being hit with ratelimits.
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default): 3 self.http_status = attr_dict['http_status'].default 4 self.url = url 5 self.body = body 6 self.retry_after = retry_after 7 self.message = __attr_factory_message(self) 8 BaseException.__init__(self, self.url,self.body,self.retry_after)
Method generated by attrs for class RateLimitedError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
49@typing.final 50class RecordState(enums.Flag): 51 """An enum for records component states.""" 52 53 NONE = 0 54 REDEEMED = 1 55 UNAVAILABLE = 2 56 OBJECTIVE_NOT_COMPLETED = 4 57 OBSCURED = 8 58 INVISIBLE = 16 59 ENTITLEMENT_UNOWNED = 32 60 CAN_EQUIP_TITLE = 64
An enum for records component states.
691@typing.final 692class Relationship(int, Enum): 693 """An enum for bungie friends relationship types.""" 694 695 UNKNOWN = 0 696 FRIEND = 1 697 INCOMING_REQUEST = 2 698 OUTGOING_REQUEST = 3
An enum for bungie friends relationship types.
215class RequestMethod(str, enums.Enum): 216 """HTTP request methods enum.""" 217 218 GET = "GET" 219 """GET methods.""" 220 POST = "POST" 221 """POST methods.""" 222 PUT = "PUT" 223 """PUT methods.""" 224 PATCH = "PATCH" 225 """PATCH methods.""" 226 DELETE = "DELETE" 227 """DELETE methods"""
HTTP request methods enum.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
208@attrs.define(auto_exc=True) 209class ResponseError(HTTPException): 210 """Standard HTTP responses exception."""
Standard HTTP responses exception.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class ResponseError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
518@typing.final 519class Stat(int, Enum): 520 """An Enum for Destiny 2 character stats.""" 521 522 NONE = 0 523 MOBILITY = 2996146975 524 RESILIENCE = 392767087 525 RECOVERY = 1943323491 526 DISCIPLINE = 1735777505 527 INTELLECT = 144602215 528 STRENGTH = 4244567218 529 LIGHT_POWER = 1935470627
An Enum for Destiny 2 character stats.
633@typing.final 634class TierType(int, Enum): 635 """An enum for a Destiny 2 item tier type.""" 636 637 UNKNOWN = 0 638 CURRENCY = 1 639 BASIC = 2 640 COMMON = 3 641 RARE = 4 642 SUPERIOR = 5 643 EXOTIC = 6
An enum for a Destiny 2 item tier type.
743@typing.final 744class TransferStatus(Flag): 745 """An enum for items transfer statuses.""" 746 747 CAN_TRANSFER = 0 748 """The item can be transferred.""" 749 IS_EQUIPPED = 1 750 """You can't transfer since the item is equipped.""" 751 NOT_TRASNFERRABLE = 2 752 """This item can not be transferred.""" 753 COULD_BE_TRANSFERRED = 4 754 """You can trasnfer the item. But the place you're trying to put it at has no space for it."""
An enum for items transfer statuses.
You can trasnfer the item. But the place you're trying to put it at has no space for it.
33class UndefinedType: 34 """An `UNDEFINED` type.""" 35 36 __instance: typing.Optional[UndefinedType] = None 37 38 def __bool__(self) -> typing.Literal[False]: 39 return False 40 41 def __int__(self) -> typing.Literal[0]: 42 return 0 43 44 def __repr__(self) -> str: 45 return "UNDEFINED" 46 47 def __str__(self) -> str: 48 return "UNDEFINED" 49 50 def __new__(cls) -> UndefinedType: 51 if cls.__instance is None: 52 o = super().__new__(cls) 53 cls.__instance = o 54 return cls.__instance
An UNDEFINED type.
75@typing.final 76class ValueUIStyle(int, enums.Enum): 77 AUTOMATIC = 0 78 FRACTION = 1 79 CHECK_BOX = 2 80 PERCENTAGE = 3 81 DATETIME = 4 82 FRACTION_FLOAT = 5 83 INTEGER = 6 84 TIME_DURATION = 7 85 HIDDEN = 8 86 MULTIPLIER = 9 87 GREEN_PIPS = 10 88 RED_PIPS = 11 89 EXPLICIT_PERCENTAGE = 12 90 RAW_FLOAT = 13 91 LEVEL_AND_REWARD = 14
An enumeration.
245@typing.final 246class Vendor(int, Enum): 247 """An Enum for all available vendors in Destiny 2.""" 248 249 ZAVALA = 69482069 250 XUR = 2190858386 251 BANSHE = 672118013 252 SPIDER = 863940356 253 SHAXX = 3603221665 254 KADI = 529635856 255 """Postmaster exo.""" 256 YUNA = 1796504621 257 """Asia servers only.""" 258 EVERVERSE = 3361454721 259 AMANDA = 460529231 260 """Amanda holiday""" 261 CROW = 3611983588 262 HAWTHORNE = 3347378076 263 ADA1 = 350061650 264 DRIFTER = 248695599 265 IKORA = 1976548992 266 SAINT = 765357505 267 """Saint-14""" 268 ERIS_MORN = 1616085565 269 SHAW_HAWN = 1816541247 270 """COSMODROME Guy""" 271 VARIKS = 2531198101
An Enum for all available vendors in Destiny 2.
532@typing.final 533class WeaponType(int, Enum): 534 """Enums for The three Destiny Weapon Types""" 535 536 NONE = 0 537 KINETIC = 1498876634 538 ENERGY = 2465295065 539 POWER = 953998645
Enums for The three Destiny Weapon Types
594def into_iter( 595 iterable: collections.Iterable[Item], 596) -> FlatIterator[Item]: 597 """Converts an iterable into an flat iterator. 598 599 Example 600 ------- 601 >>> sequence = [1,2,3] 602 >>> async for item in aiobungie.into_iter(sequence).reversed(): 603 print(item) 604 # 3 605 # 2 606 # 1 607 608 Parameters 609 ---------- 610 iterable: `typing.Iterable[Item]` 611 The iterable to convert. 612 613 Raises 614 ------ 615 `StopIteration` 616 If no elements are left in the iterator. 617 """ 618 return FlatIterator(iterable)
Converts an iterable into an flat iterator.
Example
>>> sequence = [1,2,3]
>>> async for item in aiobungie.into_iter(sequence).reversed():
print(item)
<h1 id="3">3</h1>
2
1
Parameters
- iterable (
typing.Iterable[Item]): The iterable to convert.
Raises
StopIteration: If no elements are left in the iterator.
242async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError: 243 """Generates and raise exceptions on error responses.""" 244 245 # Not a JSON response, raise immediately. 246 247 # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized 248 # request with a dummy access token. I can't really do anything about this.. 249 if response.content_type != "application/json": 250 return HTTPError( 251 f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}", 252 http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE, 253 ) 254 255 body = await response.json() 256 message: str = body.get("Message", "UNDEFINED_MESSAGE") 257 error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS") 258 message_data: dict[str, str] = body.get("MessageData", {}) 259 throttle_seconds: int = body.get("ThrottleSeconds", 0) 260 error_code: int = body.get("ErrorCode", 0) 261 262 # Standard HTTP status. 263 if response.status == http.HTTPStatus.NOT_FOUND: 264 return NotFound( 265 message=message, 266 error_code=error_code, 267 throttle_seconds=throttle_seconds, 268 url=str(response.real_url), 269 body=body, 270 headers=response.headers, 271 error_status=error_status, 272 message_data=message_data, 273 ) 274 275 elif response.status == http.HTTPStatus.FORBIDDEN: 276 return Forbidden( 277 message=message, 278 error_code=error_code, 279 throttle_seconds=throttle_seconds, 280 url=str(response.real_url), 281 body=body, 282 headers=response.headers, 283 error_status=error_status, 284 message_data=message_data, 285 ) 286 287 elif response.status == http.HTTPStatus.UNAUTHORIZED: 288 return Unauthorized( 289 message=message, 290 error_code=error_code, 291 throttle_seconds=throttle_seconds, 292 url=str(response.real_url), 293 body=body, 294 headers=response.headers, 295 error_status=error_status, 296 message_data=message_data, 297 ) 298 299 elif response.status == http.HTTPStatus.BAD_REQUEST: 300 # Membership needs to be alone. 301 if error_status == "InvalidParameters": 302 return MembershipTypeError( 303 message=message, 304 body=body, 305 headers=response.headers, 306 url=str(response.url), 307 membership_type=message_data["membershipType"], 308 required_membership=message_data["membershipInfo.membershipType"], 309 membership_id=int(message_data["membershipId"]), 310 ) 311 return BadRequest( 312 message=message, 313 body=body, 314 headers=response.headers, 315 url=str(response.url), 316 ) 317 318 status = http.HTTPStatus(response.status) 319 320 if 400 <= status < 500: 321 return ResponseError( 322 message=message, 323 error_code=error_code, 324 throttle_seconds=throttle_seconds, 325 url=str(response.real_url), 326 body=body, 327 headers=response.headers, 328 error_status=error_status, 329 message_data=message_data, 330 http_status=status, 331 ) 332 333 # Need to self handle ~5xx errors 334 elif 500 <= status < 600: 335 # No API key or method requires OAuth2 most likely. 336 if error_status in { 337 "ApiKeyMissingFromRequest", 338 "WebAuthRequired", 339 "ApiInvalidOrExpiredKey", 340 "AuthenticationInvalid", 341 "AuthorizationCodeInvalid", 342 }: 343 return Unauthorized( 344 message=message, 345 error_code=error_code, 346 throttle_seconds=throttle_seconds, 347 url=str(response.real_url), 348 body=body, 349 headers=response.headers, 350 error_status=error_status, 351 message_data=message_data, 352 ) 353 354 # Anything contains not found. 355 elif ( 356 "NotFound" in error_status or error_status == "UserCannotFindRequestedUser" 357 ): 358 return NotFound( 359 message=message, 360 error_code=error_code, 361 throttle_seconds=throttle_seconds, 362 url=str(response.real_url), 363 body=body, 364 headers=response.headers, 365 error_status=error_status, 366 message_data=message_data, 367 ) 368 369 # Other 5xx errors. 370 else: 371 return InternalServerError( 372 message=message, 373 error_code=error_code, 374 throttle_seconds=throttle_seconds, 375 url=str(response.real_url), 376 body=body, 377 headers=response.headers, 378 error_status=error_status, 379 message_data=message_data, 380 http_status=status, 381 ) 382 # Something else. 383 else: 384 return HTTPException( 385 message=message, 386 error_code=error_code, 387 throttle_seconds=throttle_seconds, 388 url=str(response.real_url), 389 body=body, 390 headers=response.headers, 391 error_status=error_status, 392 message_data=message_data, 393 http_status=status, 394 )
Generates and raise exceptions on error responses.
397def stringify_http_message(headers: collections.Mapping[str, str]) -> str: 398 return ( 399 "{ \n" 400 + "\n".join( # noqa: W503 401 f"{f' {key}'}: {value}" 402 if key not in ("Authorization", "X-API-KEY") 403 else f" {key}: HIDDEN_TOKEN" 404 for key, value in headers.items() 405 ) 406 + "\n}" # noqa: W503 407 )